BUSINESS QUESTIONS: Note: ignore the fact there is no question 1, this is due to a formatting error 2. a) Is there are a trend in injuries By Region, and is there different peaks of times of year per region? b) Analysis on the types of animals that are injured, this also by Region – is there a species that is more liable to injury in certain regions? - (cat/dog by region) c) What is the outcome? Does this differ by region?

  1. Total call volume for complaint calls: How has this trended over time?
  2. Is there a particular animal being called about the most?
  3. Do particular suburbs have different type of complaint calls? Do they call about different animals? ((MAKE A LEAFLET MAP FOR THIS!))
  1. Business Intelligence – using the insights you have found, can you predict how this might look for the upcoming year?
library(tidyverse)
library(tsibble)
library(forecast)
source("cleaning_script.R")
Rows: 31330 Columns: 7── Column specification ────────────────────────────────────────────────────────────────
Delimiter: ","
chr (6): nature, animal_type, category, suburb, date_range, city
lgl (1): responsible_office
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.Warning: Expected 2 pieces. Missing pieces filled with `NA` in 5643 rows [7, 11, 12, 18, 19, 25, 27, 29, 30, 31, 39, 44, 52, 54, 66, 67, 74, 75, 78, 81, ...].Rows: 42413 Columns: 5── Column specification ────────────────────────────────────────────────────────────────
Delimiter: ","
chr (5): Animal Type, Complaint Type, Date Received, Suburb, Electoral Division
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.Rows: 664 Columns: 12── Column specification ────────────────────────────────────────────────────────────────
Delimiter: ","
chr  (2): animal_type, outcome
dbl (10): year, ACT, NSW, NT, QLD, SA, TAS, VIC, WA, Total
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

Note; summer in Australia seasons: Summer: December - February Autumn: March - May Winter: June - August Spring: September - November

also: The ‘wet season’ in Australia’s North: November - April

https://www.mdpi.com/2076-2615/8/7/100 will useful reading for later, talk about the need to reduce euthanasia or similar and the effect this has on people

Intro: Introduce the point of the talk, talk about Australian RSPCA, talk about how the data was gathered (using the information from the websites), the PURPOSE of this investigation (which is to help the RSPCA know which areas/animals to focus their efforts on), as I’m introducing the datasets I can introduce the two different cities. First, we can talk a short bit about Australia as a whole, it’s climate, the kind of animals etc. The point here is to really set the scene before diving too deep into facts and figures, as especially a non-technical audience this will help keep them engaged and make a more holistic presentation. In my opinion, it’s always good to zoom out and see the big picture, rather than getting lost in the myopia of some csv files.

Townsville Intro: Townsville is a city on the north-eastern coast of Queensland, Australia. With a population of 180,820 as of June 2018, it is the largest settlement in North Queensland; it is unofficially considered its capital. [note: put a map of Australia with Queensland and Townsville highlighted here. Talk a little bit about the population density, urbanisation, climate, types of animals that are common here etc. Show some photos of the area too]

Brisbane Intro: Exact same as above

3.

  1. Total call volume for complaint calls: How has this trended over time?

First, let’s look at the Townsville animal complaints.

animal_complaints %>% 
  group_by(date_received) %>% 
  summarise(count = n()) %>% 
  ggplot(aes(x = date_received, y = count)) +
  geom_line() +
  scale_x_date(date_breaks = "6 months", date_labels = "%b-%y")

This shows some seasonality and also an increase then a decline. Each summer (in December) the calls are much lower, rising again each Winter. Using geom_smooth, we get:

animal_complaints %>% 
  group_by(date_received) %>% 
  summarise(count = n()) %>% 
  ggplot(aes(x = date_received, y = count)) +
  geom_smooth() +
  geom_point() +
  scale_x_date(date_breaks = "1 year", date_labels = "%y")

This shows a bit more clearly the general trend of call volume. From 2014 it steadily rises, peaking in 2017. Afterwards, it steadily declines to only slightly higher than where it started. It would be very difficult to say whether this trend will continue downward, go upward or stay relatively flat.

Note; if we have time or if it’s helpful, we will fix this graph so that quarters are properly displayed.

brisbane_complaints %>% 
  group_by(date) %>% 
  summarise(count = n()) %>% 
  ggplot(aes(x = date, y = count)) +
  geom_point() +
  geom_line() +
  scale_x_date(date_breaks = "3 months", date_labels = "%y")

Again, we see the seasonality of winter having more calls. The fact this is in both Brisbane and Townsville suggests a fairly general trend.

brisbane_complaints %>% 
  group_by(date) %>% 
  summarise(count = n()) %>% 
  ggplot(aes(x = date, y = count)) +
  geom_point() +
  geom_smooth() +
  scale_x_date(date_breaks = "1 year", date_labels = "20%y")

Other than declining a little over 2016, the number of calls sees a slow but steady increase towards 2020, being thousands more than it was in 2016 and 2017. So, the general trend is that the RSPCA are getting more complaints as time goes on. Now, this does not necessarily mean the line will continue to go up. We are also missing Q3 from 2016 so this skews the curve a little

3.b) Is there a particular animal being called about the most?

animal_complaints %>% 
  group_by(animal_type) %>% 
  ggplot(aes(x = animal_type)) +
  geom_bar()

The number of calls about dogs dwarf those about cats hugely. Let’s look at specific numbers:

animal_complaints %>% 
  group_by(animal_type) %>%
  count() %>% 
  summarise(n, 4094 / 38319)

So cats account for only 10% of the calls dogs do for Townsville! Let’s look at Brisbane:

brisbane_complaints %>% 
  group_by(type_of_animal) %>%
  count()

brisbane_complaints %>% 
  group_by(type_of_animal) %>%
  ggplot(aes(x = type_of_animal)) +
  geom_bar()

We have a lot more animal types here that we don’t in the previous data. We also have many calls about Attacks with no animal specified, many of which it is very likely they were involving dogs. However, we can’t say this for sure.

So that makes

4745 / 13334  # cats are 35% of the calls compared to dogs
[1] 0.3558572
# all other animals divided by dogs, leaving out unspecified (which we believe potentially contain a high proportion of dogs)
9457 / 13349
[1] 0.7084426

Most of the other animals have very small counts, interestingly foxes seem to make up a decent proportion of the calls regarding wild animals.

To answer the question however, it’s mainly dogs and cats, and especially dogs. Dogs are being called about more than any of the other animals combined (if we leave Unspecified to the side)

(Attack refers to the initial description of the complaint)

3. c) Do particular suburbs have different type of complaint calls? Do they call about different animals?

OK, so this one is difficult simply for the fact there is a huge amount of suburbs.

brisbane_complaints %>% 
  group_by(suburb) %>% 
  count()

# There is 192 suburbs! Certainly using a fill on a graph is not gonna work, neither is putting them on the x-axis on a bar graph.

animal_complaints %>% 
  group_by(suburb) %>% 
  count()
# 85 suburbs for Townsville

animal_complaints %>% 
  group_by(electoral_division) %>% 
  count()
# also 11 electoral divisions. Could we look at suburbs one electoral division at a time? Possibly

Idea: What about using leaflet to visualise types of complaint calls on a map?

This is more feasible with the Townsville datasets, as it has less suburbs and only 6 types of complaints. It may be necessary to try and wrangle the Brisbane data a little further to narrow down categories (for both type_of_animal and complaint_type)

FOR TOWNSVILLE WE HAVE: 85 different suburbs 6 complaint types 2 animal types

We want to break it down by suburb and complaint type, and then by suburb and animal type

animal_complaints %>% 
  ggplot(aes(x = suburb, fill = animal_type)) +
  geom_bar(position = "fill") +
  coord_flip() +
  scale_x_discrete(guide = guide_axis(n.dodge = 5))

animal_complaints %>% 
  ggplot(aes(x = suburb, fill =complaint_type)) +
  geom_bar(position = "fill") 

  #coord_flip() +
  #scale_x_discrete(guide = guide_axis(n.dodge = 5))

The challenge again, is having too many suburbs that we can’t get any useful information out of the graphs

animal_complaints %>% 
  group_by(suburb) %>% 
  count(sort = TRUE)

# let's drop any suburbs with less than 200 cases

animal_complaints %>% 
  group_by(suburb) %>% 
  summarise(count = n(), animal_type) %>% 
  filter(count >= 500) %>% 
  ggplot(aes(x = suburb, y = count, fill = animal_type)) +
  geom_col() +
  coord_flip()
`summarise()` has grouped output by 'suburb'. You can override using the `.groups` argument.

The highest count by quite a large margin is unallocated to a specific suburb.

animal_complaints %>% 
  group_by(suburb) %>% 
  summarise(count = n(), animal_type) %>% 
  filter(count >= 500) %>% 
  ggplot(aes(x = suburb, y = count, fill = animal_type)) +
  geom_col(position = "fill") +
  coord_flip() 
`summarise()` has grouped output by 'suburb'. You can override using the `.groups` argument.

At a glance, there’s no big difference on animal types. All the suburbs have a large majority of dogs. Could we do a hypothesis test to see if there is a statistically significant difference?

animal_complaints %>% 
  group_by(suburb) %>% 
  summarise(count = n(), animal_type) %>% 
  filter(count < 500 & count > 100) %>% 
  ggplot(aes(x = suburb, y = count, fill = animal_type)) +
  geom_col(position = "fill") +
  coord_flip() 
`summarise()` has grouped output by 'suburb'. You can override using the `.groups` argument.

Looking at the lower end of the population, we see an outlier. Townsville City has way more cats than any of the other suburbs. In fact, it’s almost 50/50!

Now still looking at the Townsville dataset, we’ll break it down by complaint type:

animal_complaints %>% 
  group_by(suburb) %>% 
  summarise(count = n(), complaint_type) %>% 
  filter(count >= 500 & count <= 4000) %>% 
  ggplot(aes(x = suburb, y = count, fill = complaint_type)) +
  geom_col(position = "fill") +
  coord_flip() 
`summarise()` has grouped output by 'suburb'. You can override using the `.groups` argument.

Now for the lower end of the count:

animal_complaints %>% 
  group_by(suburb) %>% 
  summarise(count = n(), complaint_type) %>% 
  filter(count < 500 & count > 50) %>% 
  ggplot(aes(x = suburb, y = count, fill = complaint_type)) +
  geom_col(position = "fill") +
  coord_flip() 
`summarise()` has grouped output by 'suburb'. You can override using the `.groups` argument.

I’m not sure much can be gleamed with so many complaint_types. Let’s try focusing more specifically.

One thing to note here, is the vast variation in tolerance for noise. Most categories are consistent except this one. Cluden for example has a small percentage of noise complaints,while Bohle Plains has a huge percentage. This requires more investigation to figure out the root cause of this:

animal_complaints %>% 
  group_by(suburb) %>% 
  summarise(count = n(), complaint_type) %>% 
  filter(count >= 500) %>% 
  filter(complaint_type == "Noise" | (complaint_type == "Attack")) %>% 
  ggplot(aes(x = suburb, y = count, fill = complaint_type)) +
  geom_col(position = "fill") +
  coord_flip() 
`summarise()` has grouped output by 'suburb'. You can override using the `.groups` argument.

animal_complaints %>% 
  group_by(suburb) %>% 
  summarise(count = n(), complaint_type) %>% 
  filter(count >= 500) %>% 
  filter(complaint_type == "Noise" | (complaint_type == "Aggressive Animal")) %>% 
  ggplot(aes(x = suburb, y = count, fill = complaint_type)) +
  geom_col(position = "fill") +
  coord_flip() 
`summarise()` has grouped output by 'suburb'. You can override using the `.groups` argument.

animal_complaints %>% 
  group_by(suburb) %>% 
  summarise(count = n(), complaint_type) %>% 
  filter(count >= 500) %>% 
  filter(complaint_type == "Wandering" | (complaint_type == "Aggressive Animal")) %>% 
  ggplot(aes(x = suburb, y = count, fill = complaint_type)) +
  geom_col(position = "fill") +
  coord_flip() 
`summarise()` has grouped output by 'suburb'. You can override using the `.groups` argument.

animal_complaints %>% 
  group_by(suburb) %>% 
  summarise(count = n(), complaint_type) %>% 
  filter(count >= 500) %>% 
  filter(complaint_type == "Enclosure" | (complaint_type == "Noise")) %>% 
  ggplot(aes(x = suburb, y = count, fill = complaint_type)) +
  geom_col(position = "fill") +
  coord_flip() 
`summarise()` has grouped output by 'suburb'. You can override using the `.groups` argument.

For the less than 500 greater than 50 groups:

animal_complaints %>% 
  group_by(suburb) %>% 
  summarise(count = n(), complaint_type) %>% 
  filter(count < 500 & count > 100) %>% 
  filter(complaint_type == "Noise" | (complaint_type == "Attack")) %>% 
  ggplot(aes(x = suburb, y = count, fill = complaint_type)) +
  geom_col(position = "fill") +
  coord_flip() 
`summarise()` has grouped output by 'suburb'. You can override using the `.groups` argument.

animal_complaints %>% 
  group_by(suburb) %>% 
  summarise(count = n(), complaint_type) %>% 
  filter(count < 500 & count > 100) %>%  
  filter(complaint_type == "Noise" | (complaint_type == "Aggressive Animal")) %>% 
  ggplot(aes(x = suburb, y = count, fill = complaint_type)) +
  geom_col(position = "fill") +
  coord_flip() 
`summarise()` has grouped output by 'suburb'. You can override using the `.groups` argument.

animal_complaints %>% 
  group_by(suburb) %>% 
  summarise(count = n(), complaint_type) %>% 
  filter(count < 500 & count > 100) %>% 
  filter(complaint_type == "Wandering" | (complaint_type == "Aggressive Animal")) %>% 
  ggplot(aes(x = suburb, y = count, fill = complaint_type)) +
  geom_col(position = "fill") +
  coord_flip() 
`summarise()` has grouped output by 'suburb'. You can override using the `.groups` argument.

animal_complaints %>% 
  group_by(suburb) %>% 
  summarise(count = n(), complaint_type) %>% 
  filter(count < 500 & count > 100) %>% 
  #filter(complaint_type == "Enclosure" | (complaint_type == "Noise")) %>% 
  ggplot(aes(x = suburb, y = count, fill = complaint_type)) +
  geom_col(position = "fill") +
  coord_flip() +
  facet_wrap(~ suburb)
`summarise()` has grouped output by 'suburb'. You can override using the `.groups` argument.

animal_complaints %>% 
  group_by(suburb) %>% 
  summarise(count = n(), complaint_type, animal_type) %>% 
  filter(count < 500 & count > 100) %>% 
  ggplot(aes(x = complaint_type, y = count, fill = complaint_type)) +
  geom_col() +
  facet_wrap(~ suburb)
`summarise()` has grouped output by 'suburb'. You can override using the `.groups` argument.

From this graph, we can see that Hyde Park has a disproportionate amount of private impounds, while Bohle plains has more noise complaints.

Potential hypothesis test:

That the level of private impounds in Hyde Park being greater is statistically significant.

That the level of noise in Bohle Plains being greater is statistically significant.

animal_complaints %>% 
  group_by(suburb) %>% 
  count() %>% 
  filter(n < 500 & n > 100)

Let’s look at the suburbs with much higher complaints now:

animal_complaints %>% 
  group_by(suburb) %>% 
  summarise(count = n(), complaint_type, animal_type) %>% 
  filter(count >= 500 & count <4000) %>% 
  ggplot(aes(x = complaint_type, y = count, fill = complaint_type)) +
  geom_col() +
  facet_wrap(~ suburb)
`summarise()` has grouped output by 'suburb'. You can override using the `.groups` argument.

2. a) Are there any major differences between regions?

  1. How do the animal outcomes differ over time?

  2. Are there any noticeable anomalies in the data?

It’s impossible to say if there’s different peaks of times of yer per region, as we only have the data for the year as a whole. Unless we look at Suburb rather than region, and break this down by time. However, I think it’d be good to use the general Autralia (nationwide) data.

Proportions overall by region and by outcome. We can see that in general, regions have pretty similar proportions across all outcomes. This won’t be the case for every year though and trends over time, that’s the more interesting stuff.

This is the same thing as before, but for animal type. Same as before, not much discernible difference between the regions.

Next is just the sum ocurrences. We can see the regions that have way more animals injured/taken in by the RSPCA. This could be a population thing, maybe these regions just have more wildlife populations etc., or even a bigger RSPCA presence leading to more cases.

So, this is the data across time (from 1999-2018), with time on the x-axis and number of occurences on the y. Faceted into graphs based on outcome, with the coloured lines representing different regions.

What can we say about this? Well, QLD has had their transfers go way up since about 2009, and in general looks like an increase in cases for them. NSW had a big spike of Currently In Care around 2004. Euthanisation in general seems to be falling out of favour (which is actually true, the RSPCA tries to do it less for various reasons, one actually being the mental health of the staff and another being lots of euthanisations leads to a negative perception of animal shelters)

Exact same as before, but faceted on animal type rather than outcome.

QLD has had a lot more wildlife cases, steadily climbing since about 2006. NSW has had a big drop in cats recently. Dogs too. Horses have gone up every region it looks like. NT has had a huge spike in cats from 2015-2016.

This one has the same x and y, but is faceted based on region. The coloured lines now represent the outcomes.

WA in 2006 had a big increase in euthanizations. VIC has had theirs steadily decreasing over time, this is reflected also in NSW, TAS and ACT.

Same as before with faceting based on region, but now the coloured lines represent the type of animal the RSPCA is dealing with.

NT has had a big spike in dogs and cats in recent years. WA had a big spike in wildlife in 2005, corresponding with their spike in euthanizations - common sense and domain knowledge tell us these are likely highly correlated. VIC’s numbers in general seem to be decreasing over time.

Looking now specifically at euthanizations, faceted by region with the lines representing euthanizations.

Now we no longer facet by region.

OK so cats and dogs have way less euthanisations. Wildlife has gone way up! Horses are too small a sample to be meaningful. Other animals have spiked then decreased.

Looking at rehomes to euthanisations, we see cats have an upward trend with less euthanisations and more rehomes, with dogs, both have gone down. Perhaps with dogs there’s a confounding factor. In fact, it seems like the RSPCA is dealing with less dogs in general.

Euthanizations for wildlife have overall gone up. Queensland is skewing the data, they’ve euthanized way more! Is this necessarily a bad thing? It could indicate a bigger RSPCA presence in the area, and more vigilance in regards to controlling the wildlife.

General thoughts:

big change in 2006 for WA; cyclone Emma March 2006 could’ve released many wild animals leading to high euthanizations (this for 2.c) different territories have different approaches;

4. Business Intelligence – using the insights you have found, can you predict how this might look for the upcoming year?

animal_outcomes %>% 
  drop_na() %>% 
  group_by(region, outcome, year) %>%
  summarize(total_injuries = sum(number_of_occurences)) %>%
  ungroup() %>% 
  filter(outcome == "Euthanized") %>% 
  ggplot(aes(x = year, y = total_injuries, color = outcome)) +
  geom_line() +
  facet_wrap(~region, scales = "free_y") +
  labs(x = "Date", y = "Number of injuries", color = "Outcome")
`summarise()` has grouped output by 'region', 'outcome'. You can override using the `.groups` argument.

Next attempt for a model

I want to predict the total cases for Australia. We won’t break it down by region. So first, let’s get our summary statistics and put it in a new variable:

animal_outcomes %>% 
  drop_na() %>% 
  group_by(outcome, animal_type, year, region) %>%
  summarize(total_injuries = sum(number_of_occurences)) %>%
  ungroup() %>% 
  filter(animal_type == "Cats" & outcome == "Euthanized") %>% 
  ggplot(aes(x = year, y = total_injuries, color = outcome)) +
  geom_line() +
  facet_wrap(~region, scales = "free_y") +
  labs(x = "Date", y = "Number of injuries", color = "Outcome", title = "Cats")
`summarise()` has grouped output by 'outcome', 'animal_type', 'year'. You can override using the `.groups` argument.

animal_outcomes %>% 
  drop_na() %>% 
  group_by(outcome, animal_type, year) %>%
  summarize(total_injuries = sum(number_of_occurences)) %>%
  ungroup() %>% 
  filter(animal_type == "Cats" & outcome == "Euthanized") %>% 
  ggplot(aes(x = year, y = total_injuries, color = outcome)) +
  geom_line() +
  #facet_wrap(~region, scales = "free_y") +
  labs(x = "Date", y = "Number of injuries", color = "Outcome", title = "Cats")
`summarise()` has grouped output by 'outcome', 'animal_type'. You can override using the `.groups` argument.

wildlife_tsbl <- animal_outcomes %>% 
  drop_na() %>% 
  filter(animal_type == "Cats" & outcome == "Euthanized") %>% 
  group_by(year) %>% 
  summarise(total_euth = sum(number_of_occurences)) %>% 
  ungroup() %>% 
  as_tsibble(key = year, index = total_euth)
# Fit ARIMA model
wildlife_arima <- wildlife_tsbl %>% 
  model(total_euth = ARIMA(total_euth))
Warning: 20 errors (1 unique) encountered for total_euth
[20] attempt to select less than one element in get1index
# Generate forecasts
wildlife_forecast <- wildlife_tsbl %>%
  model(ARIMA(total_euth)) %>% 
  forecast(h = 36)
Error in FUN(X[[i]], ...) : object 'total_euth' not found
library(tidyverse)
library(fable)
library(tsibble)
library(tsibbledata)
# We also need to use the "urca" package to be able to use the ARIMA model
library(urca)
library(tsibble)
library(fable)

wildlife_tsbl <- animal_outcomes %>% 
  drop_na() %>% 
  filter(animal_type == "Cats" & outcome == "Euthanized") %>% 
  group_by(year) %>% 
  summarise(total_euth = sum(number_of_occurences)) %>% 
  ungroup() %>%
  mutate(date = year %>% as.Date(paste0("-01-01"))) %>% 
  as_tsibble(key = year, index = date)

wildlife_arima <- wildlife_tsbl %>% 
  model(ARIMA(total_euth))

wildlife_forecast <- wildlife_arima %>% 
  forecast(h = 36)

wildlife_forecast
NA
NA
wildlife_forecast %>% 
  autoplot() + 
  scale_y_continuous(limits = c(0, max(wildlife_tsbl$total_euth, na.rm = TRUE) * 1.2))

library(fable)
library(tsibbledata)
library(dplyr)
library(ggplot2)


# Create tsibble
wildlife_tsbl <- animal_outcomes %>% 
  drop_na() %>% 
  filter(animal_type == "Cats" & outcome == "Euthanized") %>% 
  group_by(year) %>% 
  summarise(total_euth = sum(number_of_occurences)) %>% 
  ungroup() %>% 
  as_tsibble(index = year)

# Fit ARIMA model
wildlife_arima <- wildlife_tsbl %>% 
  model(ARIMA(total_euth))
Warning: 1 error encountered for ARIMA(total_euth)
[1] .data contains implicit gaps in time. You should check your data and convert implicit gaps into explicit missing values using `tsibble::fill_gaps()` if required.
# Generate forecasts
wildlife_fcst <- wildlife_arima %>% 
  forecast(h = 36)

# Add source column to forecast
wildlife_fcst %>%
  mutate(source = "forecast") %>%
  select(source, year, .mean) %>%
  bind_rows(wildlife_tsbl %>% as_tibble() %>% mutate(source = "actual")) %>%
  
  # Plot the actuals and forecasts
  ggplot(aes(x = year, y = .mean, color = source)) +
  geom_line() +
  labs(y = "Total Euthanized Cats") +
  scale_color_manual(values = c("actual" = "black", "forecast" = "red")) +
  theme_minimal()
Error in `build_fable()`:
! Can't subset columns that don't exist.
✖ Column `total_euth` doesn't exist.
Backtrace:
 1. ... %>% ggplot(aes(x = year, y = .mean, color = source))
 6. fabletools:::select.fbl_ts(., source, year, .mean)
 7. fabletools:::restore_fable(res, .data)
 8. fabletools:::build_fable(data, response = response_vars(template), distribution = !!distribution_var(template))
wildlife_ts
Time Series:
Start = 1 
End = 20 
Frequency = 1 
 [1] 31202 32901 31009 30449 35934 31941 37010 33343 42731 39495 38642 37177 24651 19464
[15] 15491 17398 16205 14563 12610 11740
library(tsibble)
library(fable)

# Convert ts object to tsibble
wildlife_tsbl <- as_tsibble(wildlife_ts, index = "year")

# Fit ARIMA model to tsibble
wildlife_arima <- wildlife_tsbl %>% 
  model(ARIMA(value))

# Generate forecasts
wildlife_forecast <- wildlife_arima %>% 
  forecast(h = 36)

# Convert forecast to a tsibble
wildlife_fcst <- as_tsibble(wildlife_forecast, key = "year")

# Plot the forecast
wildlife_fcst %>%
  ggplot(aes(x = year, y = .mean, color = source)) +
  geom_line()
Error in `geom_line()`:
! Problem while computing aesthetics.
ℹ Error occurred in the 1st layer.
Caused by error in `compute_aesthetics()`:
! Aesthetics are not valid data columns.
✖ The following aesthetics are invalid:
✖ `x = NULL`
✖ `colour = NULL`
ℹ Did you mistype the name of a data column or forget to add `after_stat()`?
Backtrace:
  1. base (local) `<fn>`(x)
  2. ggplot2:::print.ggplot(x)
  4. ggplot2:::ggplot_build.ggplot(x)
  5. ggplot2:::by_layer(...)
 12. ggplot2 (local) f(l = layers[[i]], d = data[[i]])
 13. l$compute_aesthetics(d, plot)
 14. ggplot2 (local) compute_aesthetics(..., self = self)

library(tsibble)
library(fable)
library(ggplot2)

# Convert ts object to tsibble
wildlife_tsbl <- as_tsibble(wildlife_ts, index = "year")

# Fit ARIMA model to tsibble
wildlife_arima <- wildlife_tsbl %>% 
  model(ARIMA(value))

# Generate forecasts
wildlife_forecast <- wildlife_arima %>% 
  forecast(h = 36)

# Convert forecast to a tsibble
wildlife_fcst <- as_tsibble(wildlife_forecast, key = "year")

# Plot the forecast
wildlife_fcst %>%
  ggplot(aes(x = index, y = .mean, color = .model)) +
  geom_line()

NA
NA
names(wildlife_fcst)
[1] ".model" "index"  "value"  ".mean" 

# grouping the data and creating a variable
animal_complaints_grouped <- animal_complaints %>% 
  group_by(date_received) %>% 
  summarise(count = n()) %>% 
  arrange(date_received)

myts <- ts(animal_complaints_grouped$count, frequency = 12, start = c(year(animal_complaints_grouped$date_received[1]), month(animal_complaints_grouped$date_received[1])))

myforecast <- forecast(auto.arima(myts), h = 24)
Error in switch(names(interval), day = "days", hour = "hours", minute = "mins",  : 
  EXPR must be a length 1 vector
myts_forecast <- function(myts, h, interval) {
  library(forecast)
  
  # Set the appropriate time interval for the forecast horizon
  interval <- switch(interval,
                     "day" = "days",
                     "hour" = "hours",
                     "minute" = "mins",
                     "second" = "secs")
  
  # Create the forecast
  myforecast <- forecast(myts, h = 24, level = c(80, 95), 
                       xreg = mydummies, 
                       lambda = NULL, biasadj = TRUE,
                       fan = FALSE, 
                       interval = "week")

  
  # Print the forecast table
  print(myforecast)
  
  # Plot the forecast
  autoplot(myforecast)
}
print(interval)
function (start = NULL, end = NULL, tzone = tz(start)) 
{
    if (is.character(start) && is.null(end)) {
        return(parse_interval(start, tzone))
    }
    if (length(start) == 0 || length(end) == 0) {
        if (is.null(start) && missing(tzone)) {
            tzone <- "UTC"
        }
        start <- POSIXct(tz = tzone)
        return(new("Interval", numeric(), start = start, tzone = tzone))
    }
    if (is.Date(start)) 
        start <- date_to_posix(start)
    if (is.Date(end)) 
        end <- date_to_posix(end)
    force(tzone)
    start <- as_POSIXct(start, tzone)
    end <- as_POSIXct(end, tzone)
    span <- as.numeric(end) - as.numeric(start)
    starts <- start + rep(0, length(span))
    if (tzone != tz(starts)) 
        starts <- with_tz(starts, tzone)
    new("Interval", span, start = starts, tzone = tzone)
}
<bytecode: 0x7fa7b16da468>
<environment: namespace:lubridate>
print(class(interval))
[1] "function"
print(length(interval))
[1] 1
# Create a sequence of dates for the next 24 months
dates <- seq(as.Date("2023-03-01"), by = "month", length.out = 24)

# Create a time series object with random values for demonstration purposes
values <- rnorm(24)
myts <- ts(values, start = c(year(dates[1]), month(dates[1])), frequency = 12)

# Plot the time series
plot(myts)


# Forecast the next 24 months
library(forecast)
myforecast <- forecast(myts, h = 24)
Error in UseMethod("forecast") : 
  no applicable method for 'forecast' applied to an object of class "ts"

Another, FINAL attempt

This is quite difficult indeed. Let’s try go slowly using the notes, build it bit by bit.

So all we wanna do, is plot the next few years, and see what it will look like on the graph. Nothing needs to be too fancy. We will keep it simple, create a simple model. Then plot this. OK.

So first, it needs to be tsibble.

It has now been converted to a tsibble, with date_received as the index. As it contains only a single time series, a key should not be necessary.

library(tidyverse)
library(fable)
library(tsibble)
library(tsibbledata)
# We also need to use the "urca" package to be able to use the ARIMA model
library(urca)

We load in all packages just to be 100% sure they are loaded.

# next, we will use autoplot
autoplot(animal_complaints_tsibble)
Plot variable not specified, automatically selected `.vars = count`

Our data is there. Now, we will fit a model.

library(purrr)

fit <- animal_complaints_tsibble %>%
  model(
    snaive = SNAIVE(count),
    mean_model = MEAN(count),
    arima = ARIMA(count)
  )
fit

# fit %>% 
#   dmap(unlist)

Here is our mable, also called model table. Each cell corresponds to a fitted model. Now, we will calculate some forecasts using our model.

forecast_1 <- fit %>%
  fabletools::forecast(h = 36)
forecast_1

OK, looking good so far.

forecast_1 %>%
  autoplot(animal_complaints_tsibble)

Let’s make our model look pretty and have less clutter

forecast_1 %>%
  filter(.model == "arima") %>% 
  autoplot(animal_complaints_tsibble, level = 95) +
  scale_x_yearmonth(date_breaks = "6 months", date_labels = "%b %y") + 
  labs(title = "Townsville Complaint Calls with Prediction",
       x = "Time",
       y = "Number of Calls") +
  theme_economist() +
  theme(axis.text.x = element_text(angle = 45, vjust = 1, family = "mono", face = "bold", size = 7),
        #axis.ticks.x = 
        axis.title.y = element_text(vjust = 3.2),
        title = element_text(family = "mono", face = "bold"),
        plot.title = element_text(hjust = 0.4),
        legend.title = element_blank(),
        legend.position = "none") +
        annotate("rect", xmin = as.Date("2014-06-01"), xmax = as.Date("2014-08-01"), ymin = -Inf, ymax = Inf, fill = "gray70", alpha = 0.3) +
        annotate("rect", xmin = as.Date("2015-06-01"), xmax = as.Date("2015-08-01"), ymin = -Inf, ymax = Inf, fill = "gray70", alpha = 0.3) +
        annotate("rect", xmin = as.Date("2016-06-01"), xmax = as.Date("2016-08-01"), ymin = -Inf, ymax = Inf, fill = "gray70", alpha = 0.3) +
        annotate("rect", xmin = as.Date("2017-06-01"), xmax = as.Date("2017-08-01"), ymin = -Inf, ymax = Inf, fill = "gray70", alpha = 0.3) +
        annotate("rect", xmin = as.Date("2018-06-01"), xmax = as.Date("2018-08-01"), ymin = -Inf, ymax = Inf, fill = "gray70", alpha = 0.3) +
        annotate("rect", xmin = as.Date("2019-06-01"), xmax = as.Date("2019-08-01"), ymin = -Inf, ymax = Inf, fill = "gray70", alpha = 0.3) +
        annotate("rect", xmin = as.Date("2020-06-01"), xmax = as.Date("2020-08-01"), ymin = -Inf, ymax = Inf, fill = "gray70", alpha = 0.3) +
        annotate("rect", xmin = as.Date("2021-06-01"), xmax = as.Date("2021-08-01"), ymin = -Inf, ymax = Inf, fill = "gray70", alpha = 0.3) +
        annotate("rect", xmin = as.Date("2022-06-01"), xmax = as.Date("2022-08-01"), ymin = -Inf, ymax = Inf, fill = "gray70", alpha = 0.3) +
        annotate("rect", xmin = as.Date("2023-06-01"), xmax = as.Date("2023-08-01"), ymin = -Inf, ymax = Inf, fill = "gray70", alpha = 0.3)

NA

So I was also tasked with creating a model, to predict how things might look for the next few years. I focused specifically on the Townsville data, as this was most suitable for forecasting. I used something called the “ARIMA” model, the inner workings of which are quite complicated, but basically it predicts the future based on the past, and is quite good when it comes to seasonal data like I have here. The blue line is the prediction, and the light blue area you see highlighted around it is the confidence interval. Think of this like a margin of error, and it basically means that 95% of the time, our model will predict results in this area.

This model suggests that roughly the same pattern will continue as before, with fairly steady volume of calls and high peaks in Winter. But bear in mind this model is quite limited and shouldn’t be taken as fact; for example, it doesn’t take into account natural disasters and other events which could cause an increase in complaint calls.

Documentation note

Fix or discuss the error of NT and NSW swapping for 2016-2018

LS0tCnRpdGxlOiAiQW5hbHlzaXMiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCkJVU0lORVNTIFFVRVNUSU9OUzoKTm90ZTogaWdub3JlIHRoZSBmYWN0IHRoZXJlIGlzIG5vIHF1ZXN0aW9uIDEsIHRoaXMgaXMgZHVlIHRvIGEgZm9ybWF0dGluZyBlcnJvcgoyLiAKYSkgSXMgdGhlcmUgYXJlIGEgdHJlbmQgaW4gaW5qdXJpZXMgQnkgUmVnaW9uLCBhbmQgaXMgdGhlcmUgZGlmZmVyZW50IHBlYWtzIG9mIHRpbWVzIG9mIHllYXIgcGVyIHJlZ2lvbj8KYikgQW5hbHlzaXMgb24gdGhlIHR5cGVzIG9mIGFuaW1hbHMgdGhhdCBhcmUgaW5qdXJlZCwgdGhpcyBhbHNvIGJ5IFJlZ2lvbiDigJMgaXMgdGhlcmUgYSBzcGVjaWVzIHRoYXQgaXMgbW9yZSBsaWFibGUgdG8gaW5qdXJ5IGluIGNlcnRhaW4gcmVnaW9ucz8gLSAoY2F0L2RvZyBieSByZWdpb24pCmMpIFdoYXQgaXMgdGhlIG91dGNvbWU/IERvZXMgdGhpcyBkaWZmZXIgYnkgcmVnaW9uPwoKMy4KYSkgVG90YWwgY2FsbCB2b2x1bWUgZm9yIGNvbXBsYWludCBjYWxsczogSG93IGhhcyB0aGlzIHRyZW5kZWQgb3ZlciB0aW1lPwpiKSBJcyB0aGVyZSBhIHBhcnRpY3VsYXIgYW5pbWFsIGJlaW5nIGNhbGxlZCBhYm91dCB0aGUgbW9zdD8KYykgRG8gcGFydGljdWxhciBzdWJ1cmJzIGhhdmUgZGlmZmVyZW50IHR5cGUgb2YgY29tcGxhaW50IGNhbGxzPyBEbyB0aGV5IGNhbGwgYWJvdXQgZGlmZmVyZW50IGFuaW1hbHM/ICgoTUFLRSBBIExFQUZMRVQgTUFQIEZPUiBUSElTISkpCgo0LgpCdXNpbmVzcyBJbnRlbGxpZ2VuY2Ug4oCTIHVzaW5nIHRoZSBpbnNpZ2h0cyB5b3UgaGF2ZSBmb3VuZCwgY2FuIHlvdSBwcmVkaWN0IGhvdyB0aGlzIG1pZ2h0IGxvb2sgZm9yIHRoZSB1cGNvbWluZyB5ZWFyPwoKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHRzaWJibGUpCmxpYnJhcnkoZm9yZWNhc3QpCnNvdXJjZSgiY2xlYW5pbmdfc2NyaXB0LlIiKQpgYGAKCk5vdGU7IHN1bW1lciBpbiBBdXN0cmFsaWEgc2Vhc29uczoKU3VtbWVyOiBEZWNlbWJlciAtIEZlYnJ1YXJ5CkF1dHVtbjogTWFyY2ggLSBNYXkKV2ludGVyOiBKdW5lIC0gQXVndXN0ClNwcmluZzogU2VwdGVtYmVyIC0gTm92ZW1iZXIKCmFsc286IFRoZSAnd2V0IHNlYXNvbicgaW4gQXVzdHJhbGlhJ3MgTm9ydGg6IE5vdmVtYmVyIC0gQXByaWwKCmh0dHBzOi8vd3d3Lm1kcGkuY29tLzIwNzYtMjYxNS84LzcvMTAwICAgd2lsbCB1c2VmdWwgcmVhZGluZyBmb3IgbGF0ZXIsIHRhbGsgYWJvdXQgdGhlIG5lZWQgdG8gcmVkdWNlIGV1dGhhbmFzaWEgb3Igc2ltaWxhciBhbmQgdGhlIGVmZmVjdCB0aGlzIGhhcyBvbiBwZW9wbGUKCkludHJvOgpJbnRyb2R1Y2UgdGhlIHBvaW50IG9mIHRoZSB0YWxrLCB0YWxrIGFib3V0IEF1c3RyYWxpYW4gUlNQQ0EsIHRhbGsgYWJvdXQgaG93IHRoZSBkYXRhIHdhcyBnYXRoZXJlZCAodXNpbmcgdGhlIGluZm9ybWF0aW9uIGZyb20gdGhlIHdlYnNpdGVzKSwgdGhlIFBVUlBPU0Ugb2YgdGhpcyBpbnZlc3RpZ2F0aW9uICh3aGljaCBpcyB0byBoZWxwIHRoZSBSU1BDQSBrbm93IHdoaWNoIGFyZWFzL2FuaW1hbHMgdG8gZm9jdXMgdGhlaXIgZWZmb3J0cyBvbiksIGFzIEknbSBpbnRyb2R1Y2luZyB0aGUgZGF0YXNldHMgSSBjYW4gaW50cm9kdWNlIHRoZSB0d28gZGlmZmVyZW50IGNpdGllcy4gRmlyc3QsIHdlIGNhbiB0YWxrIGEgc2hvcnQgYml0IGFib3V0IEF1c3RyYWxpYSBhcyBhIHdob2xlLCBpdCdzIGNsaW1hdGUsIHRoZSBraW5kIG9mIGFuaW1hbHMgZXRjLiBUaGUgcG9pbnQgaGVyZSBpcyB0byByZWFsbHkgc2V0IHRoZSBzY2VuZSBiZWZvcmUgZGl2aW5nIHRvbyBkZWVwIGludG8gZmFjdHMgYW5kIGZpZ3VyZXMsIGFzIGVzcGVjaWFsbHkgYSBub24tdGVjaG5pY2FsIGF1ZGllbmNlIHRoaXMgd2lsbCBoZWxwIGtlZXAgdGhlbSBlbmdhZ2VkIGFuZCBtYWtlIGEgbW9yZSBob2xpc3RpYyBwcmVzZW50YXRpb24uIEluIG15IG9waW5pb24sIGl0J3MgYWx3YXlzIGdvb2QgdG8gem9vbSBvdXQgYW5kIHNlZSB0aGUgYmlnIHBpY3R1cmUsIHJhdGhlciB0aGFuIGdldHRpbmcgbG9zdCBpbiB0aGUgbXlvcGlhIG9mIHNvbWUgY3N2IGZpbGVzLgoKVG93bnN2aWxsZSBJbnRybzoKVG93bnN2aWxsZSBpcyBhIGNpdHkgb24gdGhlIG5vcnRoLWVhc3Rlcm4gY29hc3Qgb2YgUXVlZW5zbGFuZCwgQXVzdHJhbGlhLiBXaXRoIGEgcG9wdWxhdGlvbiBvZiAxODAsODIwIGFzIG9mIEp1bmUgMjAxOCwgaXQgaXMgdGhlIGxhcmdlc3Qgc2V0dGxlbWVudCBpbiBOb3J0aCBRdWVlbnNsYW5kOyBpdCBpcyB1bm9mZmljaWFsbHkgY29uc2lkZXJlZCBpdHMgY2FwaXRhbC4gW25vdGU6IHB1dCBhIG1hcCBvZiBBdXN0cmFsaWEgd2l0aCBRdWVlbnNsYW5kIGFuZCBUb3duc3ZpbGxlIGhpZ2hsaWdodGVkIGhlcmUuIFRhbGsgYSBsaXR0bGUgYml0IGFib3V0IHRoZSBwb3B1bGF0aW9uIGRlbnNpdHksIHVyYmFuaXNhdGlvbiwgY2xpbWF0ZSwgdHlwZXMgb2YgYW5pbWFscyB0aGF0IGFyZSBjb21tb24gaGVyZSBldGMuIFNob3cgc29tZSBwaG90b3Mgb2YgdGhlIGFyZWEgdG9vXQoKQnJpc2JhbmUgSW50cm86CkV4YWN0IHNhbWUgYXMgYWJvdmUKCiMjIyAzLgphKSBUb3RhbCBjYWxsIHZvbHVtZSBmb3IgY29tcGxhaW50IGNhbGxzOiBIb3cgaGFzIHRoaXMgdHJlbmRlZCBvdmVyIHRpbWU/CgpGaXJzdCwgbGV0J3MgbG9vayBhdCB0aGUgVG93bnN2aWxsZSBhbmltYWwgY29tcGxhaW50cy4KYGBge3J9CmFuaW1hbF9jb21wbGFpbnRzICU+JSAKICBncm91cF9ieShkYXRlX3JlY2VpdmVkKSAlPiUgCiAgc3VtbWFyaXNlKGNvdW50ID0gbigpKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gZGF0ZV9yZWNlaXZlZCwgeSA9IGNvdW50KSkgKwogIGdlb21fbGluZSgpICsKICBzY2FsZV94X2RhdGUoZGF0ZV9icmVha3MgPSAiNiBtb250aHMiLCBkYXRlX2xhYmVscyA9ICIlYi0leSIpCmBgYApUaGlzIHNob3dzIHNvbWUgc2Vhc29uYWxpdHkgYW5kIGFsc28gYW4gaW5jcmVhc2UgdGhlbiBhIGRlY2xpbmUuIEVhY2ggc3VtbWVyIChpbiBEZWNlbWJlcikgdGhlIGNhbGxzIGFyZSBtdWNoIGxvd2VyLCByaXNpbmcgYWdhaW4gZWFjaCBXaW50ZXIuIFVzaW5nIGdlb21fc21vb3RoLCB3ZSBnZXQ6CgpgYGB7cn0KYW5pbWFsX2NvbXBsYWludHMgJT4lIAogIGdyb3VwX2J5KGRhdGVfcmVjZWl2ZWQpICU+JSAKICBzdW1tYXJpc2UoY291bnQgPSBuKCkpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBkYXRlX3JlY2VpdmVkLCB5ID0gY291bnQpKSArCiAgZ2VvbV9zbW9vdGgoKSArCiAgZ2VvbV9wb2ludCgpICsKICBzY2FsZV94X2RhdGUoZGF0ZV9icmVha3MgPSAiMSB5ZWFyIiwgZGF0ZV9sYWJlbHMgPSAiJXkiKQpgYGAKClRoaXMgc2hvd3MgYSBiaXQgbW9yZSBjbGVhcmx5IHRoZSBnZW5lcmFsIHRyZW5kIG9mIGNhbGwgdm9sdW1lLiBGcm9tIDIwMTQgaXQgc3RlYWRpbHkgcmlzZXMsIHBlYWtpbmcgaW4gMjAxNy4gQWZ0ZXJ3YXJkcywgaXQgc3RlYWRpbHkgZGVjbGluZXMgdG8gb25seSBzbGlnaHRseSBoaWdoZXIgdGhhbiB3aGVyZSBpdCBzdGFydGVkLiBJdCB3b3VsZCBiZSB2ZXJ5IGRpZmZpY3VsdCB0byBzYXkgd2hldGhlciB0aGlzIHRyZW5kIHdpbGwgY29udGludWUgZG93bndhcmQsIGdvIHVwd2FyZCBvciBzdGF5IHJlbGF0aXZlbHkgZmxhdC4KCgoKCgoKCk5vdGU7IGlmIHdlIGhhdmUgdGltZSBvciBpZiBpdCdzIGhlbHBmdWwsIHdlIHdpbGwgZml4IHRoaXMgZ3JhcGggc28gdGhhdCBxdWFydGVycyBhcmUgcHJvcGVybHkgZGlzcGxheWVkLgpgYGB7cn0KYnJpc2JhbmVfY29tcGxhaW50cyAlPiUgCiAgZ3JvdXBfYnkoZGF0ZSkgJT4lIAogIHN1bW1hcmlzZShjb3VudCA9IG4oKSkgJT4lIAogIGdncGxvdChhZXMoeCA9IGRhdGUsIHkgPSBjb3VudCkpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fbGluZSgpICsKICBzY2FsZV94X2RhdGUoZGF0ZV9icmVha3MgPSAiMyBtb250aHMiLCBkYXRlX2xhYmVscyA9ICIleSIpCmBgYAoKQWdhaW4sIHdlIHNlZSB0aGUgc2Vhc29uYWxpdHkgb2Ygd2ludGVyIGhhdmluZyBtb3JlIGNhbGxzLiBUaGUgZmFjdCB0aGlzIGlzIGluIGJvdGggQnJpc2JhbmUgYW5kIFRvd25zdmlsbGUgc3VnZ2VzdHMgYSBmYWlybHkgZ2VuZXJhbCB0cmVuZC4KCmBgYHtyfQpicmlzYmFuZV9jb21wbGFpbnRzICU+JSAKICBncm91cF9ieShkYXRlKSAlPiUgCiAgc3VtbWFyaXNlKGNvdW50ID0gbigpKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gZGF0ZSwgeSA9IGNvdW50KSkgKwogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV9zbW9vdGgoKSArCiAgc2NhbGVfeF9kYXRlKGRhdGVfYnJlYWtzID0gIjEgeWVhciIsIGRhdGVfbGFiZWxzID0gIjIwJXkiKQpgYGAKCk90aGVyIHRoYW4gZGVjbGluaW5nIGEgbGl0dGxlIG92ZXIgMjAxNiwgdGhlIG51bWJlciBvZiBjYWxscyBzZWVzIGEgc2xvdyBidXQgc3RlYWR5IGluY3JlYXNlIHRvd2FyZHMgMjAyMCwgYmVpbmcgdGhvdXNhbmRzIG1vcmUgdGhhbiBpdCB3YXMgaW4gMjAxNiBhbmQgMjAxNy4gU28sIHRoZSBnZW5lcmFsIHRyZW5kIGlzIHRoYXQgdGhlIFJTUENBIGFyZSBnZXR0aW5nIG1vcmUgY29tcGxhaW50cyBhcyB0aW1lIGdvZXMgb24uIE5vdywgdGhpcyBkb2VzIG5vdCBuZWNlc3NhcmlseSBtZWFuIHRoZSBsaW5lIHdpbGwgY29udGludWUgdG8gZ28gdXAuIFdlIGFyZSBhbHNvIG1pc3NpbmcgUTMgZnJvbSAyMDE2IHNvIHRoaXMgc2tld3MgdGhlIGN1cnZlIGEgbGl0dGxlCgoKCiMjIyAzLmIpIElzIHRoZXJlIGEgcGFydGljdWxhciBhbmltYWwgYmVpbmcgY2FsbGVkIGFib3V0IHRoZSBtb3N0PwoKYGBge3J9CmFuaW1hbF9jb21wbGFpbnRzICU+JSAKICBncm91cF9ieShhbmltYWxfdHlwZSkgJT4lIAogIGdncGxvdChhZXMoeCA9IGFuaW1hbF90eXBlKSkgKwogIGdlb21fYmFyKCkKYGBgCgpUaGUgbnVtYmVyIG9mIGNhbGxzIGFib3V0IGRvZ3MgZHdhcmYgdGhvc2UgYWJvdXQgY2F0cyBodWdlbHkuIExldCdzIGxvb2sgYXQgc3BlY2lmaWMgbnVtYmVyczoKYGBge3J9CmFuaW1hbF9jb21wbGFpbnRzICU+JSAKICBncm91cF9ieShhbmltYWxfdHlwZSkgJT4lCiAgY291bnQoKSAlPiUgCiAgc3VtbWFyaXNlKG4sIDQwOTQgLyAzODMxOSkKYGBgCgpTbyBjYXRzIGFjY291bnQgZm9yIG9ubHkgMTAlIG9mIHRoZSBjYWxscyBkb2dzIGRvIGZvciBUb3duc3ZpbGxlISBMZXQncyBsb29rIGF0IEJyaXNiYW5lOgoKYGBge3J9CmJyaXNiYW5lX2NvbXBsYWludHMgJT4lIAogIGdyb3VwX2J5KHR5cGVfb2ZfYW5pbWFsKSAlPiUKICBjb3VudCgpCgpicmlzYmFuZV9jb21wbGFpbnRzICU+JSAKICBncm91cF9ieSh0eXBlX29mX2FuaW1hbCkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gdHlwZV9vZl9hbmltYWwpKSArCiAgZ2VvbV9iYXIoKQpgYGAKCldlIGhhdmUgYSBsb3QgbW9yZSBhbmltYWwgdHlwZXMgaGVyZSB0aGF0IHdlIGRvbid0IGluIHRoZSBwcmV2aW91cyBkYXRhLiBXZSBhbHNvIGhhdmUgbWFueSBjYWxscyBhYm91dCBBdHRhY2tzIHdpdGggbm8gYW5pbWFsIHNwZWNpZmllZCwgbWFueSBvZiB3aGljaCBpdCBpcyB2ZXJ5IGxpa2VseSB0aGV5IHdlcmUgaW52b2x2aW5nIGRvZ3MuIEhvd2V2ZXIsIHdlIGNhbid0IHNheSB0aGlzIGZvciBzdXJlLgoKU28gdGhhdCBtYWtlcyAKYGBge3J9CjQ3NDUgLyAxMzMzNCAgIyBjYXRzIGFyZSAzNSUgb2YgdGhlIGNhbGxzIGNvbXBhcmVkIHRvIGRvZ3MKCgoKIyBhbGwgb3RoZXIgYW5pbWFscyBkaXZpZGVkIGJ5IGRvZ3MsIGxlYXZpbmcgb3V0IHVuc3BlY2lmaWVkICh3aGljaCB3ZSBiZWxpZXZlIHBvdGVudGlhbGx5IGNvbnRhaW4gYSBoaWdoIHByb3BvcnRpb24gb2YgZG9ncykKOTQ1NyAvIDEzMzQ5CmBgYAoKTW9zdCBvZiB0aGUgb3RoZXIgYW5pbWFscyBoYXZlIHZlcnkgc21hbGwgY291bnRzLCBpbnRlcmVzdGluZ2x5IGZveGVzIHNlZW0gdG8gbWFrZSB1cCBhIGRlY2VudCBwcm9wb3J0aW9uIG9mIHRoZSBjYWxscyByZWdhcmRpbmcgd2lsZCBhbmltYWxzLgoKVG8gYW5zd2VyIHRoZSBxdWVzdGlvbiBob3dldmVyLCBpdCdzIG1haW5seSBkb2dzIGFuZCBjYXRzLCBhbmQgZXNwZWNpYWxseSBkb2dzLiBEb2dzIGFyZSBiZWluZyBjYWxsZWQgYWJvdXQgbW9yZSB0aGFuIGFueSBvZiB0aGUgb3RoZXIgYW5pbWFscyBjb21iaW5lZCAoaWYgd2UgbGVhdmUgVW5zcGVjaWZpZWQgdG8gdGhlIHNpZGUpCgooQXR0YWNrIHJlZmVycyB0byB0aGUgaW5pdGlhbCBkZXNjcmlwdGlvbiBvZiB0aGUgY29tcGxhaW50KQoKCiMjIyAzLiBjKSBEbyBwYXJ0aWN1bGFyIHN1YnVyYnMgaGF2ZSBkaWZmZXJlbnQgdHlwZSBvZiBjb21wbGFpbnQgY2FsbHM/IERvIHRoZXkgY2FsbCBhYm91dCBkaWZmZXJlbnQgYW5pbWFscz8KCk9LLCBzbyB0aGlzIG9uZSBpcyBkaWZmaWN1bHQgc2ltcGx5IGZvciB0aGUgZmFjdCB0aGVyZSBpcyBhIGh1Z2UgYW1vdW50IG9mIHN1YnVyYnMuCmBgYHtyfQpicmlzYmFuZV9jb21wbGFpbnRzICU+JSAKICBncm91cF9ieShzdWJ1cmIpICU+JSAKICBjb3VudCgpCgojIFRoZXJlIGlzIDE5MiBzdWJ1cmJzISBDZXJ0YWlubHkgdXNpbmcgYSBmaWxsIG9uIGEgZ3JhcGggaXMgbm90IGdvbm5hIHdvcmssIG5laXRoZXIgaXMgcHV0dGluZyB0aGVtIG9uIHRoZSB4LWF4aXMgb24gYSBiYXIgZ3JhcGguCgphbmltYWxfY29tcGxhaW50cyAlPiUgCiAgZ3JvdXBfYnkoc3VidXJiKSAlPiUgCiAgY291bnQoKQojIDg1IHN1YnVyYnMgZm9yIFRvd25zdmlsbGUKCmFuaW1hbF9jb21wbGFpbnRzICU+JSAKICBncm91cF9ieShlbGVjdG9yYWxfZGl2aXNpb24pICU+JSAKICBjb3VudCgpCiMgYWxzbyAxMSBlbGVjdG9yYWwgZGl2aXNpb25zLiBDb3VsZCB3ZSBsb29rIGF0IHN1YnVyYnMgb25lIGVsZWN0b3JhbCBkaXZpc2lvbiBhdCBhIHRpbWU/IFBvc3NpYmx5CmBgYAoKSWRlYTogV2hhdCBhYm91dCB1c2luZyBsZWFmbGV0IHRvIHZpc3VhbGlzZSB0eXBlcyBvZiBjb21wbGFpbnQgY2FsbHMgb24gYSBtYXA/CgpUaGlzIGlzIG1vcmUgZmVhc2libGUgd2l0aCB0aGUgVG93bnN2aWxsZSBkYXRhc2V0cywgYXMgaXQgaGFzIGxlc3Mgc3VidXJicyBhbmQgb25seSA2IHR5cGVzIG9mIGNvbXBsYWludHMuIEl0IG1heSBiZSBuZWNlc3NhcnkgdG8gdHJ5IGFuZCB3cmFuZ2xlIHRoZSBCcmlzYmFuZSBkYXRhIGEgbGl0dGxlIGZ1cnRoZXIgdG8gbmFycm93IGRvd24gY2F0ZWdvcmllcyAoZm9yIGJvdGggdHlwZV9vZl9hbmltYWwgYW5kIGNvbXBsYWludF90eXBlKQoKRk9SIFRPV05TVklMTEUgV0UgSEFWRToKODUgZGlmZmVyZW50IHN1YnVyYnMKNiBjb21wbGFpbnQgdHlwZXMKMiBhbmltYWwgdHlwZXMKCldlIHdhbnQgdG8gYnJlYWsgaXQgZG93biBieSBzdWJ1cmIgYW5kIGNvbXBsYWludCB0eXBlLCBhbmQgdGhlbiBieSBzdWJ1cmIgYW5kIGFuaW1hbCB0eXBlCmBgYHtyfQphbmltYWxfY29tcGxhaW50cyAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gc3VidXJiLCBmaWxsID0gYW5pbWFsX3R5cGUpKSArCiAgZ2VvbV9iYXIocG9zaXRpb24gPSAiZmlsbCIpICsKICBjb29yZF9mbGlwKCkgKwogIHNjYWxlX3hfZGlzY3JldGUoZ3VpZGUgPSBndWlkZV9heGlzKG4uZG9kZ2UgPSA1KSkKYGBgCgpgYGB7cn0KYW5pbWFsX2NvbXBsYWludHMgJT4lIAogIGdncGxvdChhZXMoeCA9IHN1YnVyYiwgZmlsbCA9Y29tcGxhaW50X3R5cGUpKSArCiAgZ2VvbV9iYXIocG9zaXRpb24gPSAiZmlsbCIpIAogICNjb29yZF9mbGlwKCkgKwogICNzY2FsZV94X2Rpc2NyZXRlKGd1aWRlID0gZ3VpZGVfYXhpcyhuLmRvZGdlID0gNSkpCmBgYAoKVGhlIGNoYWxsZW5nZSBhZ2FpbiwgaXMgaGF2aW5nIHRvbyBtYW55IHN1YnVyYnMgdGhhdCB3ZSBjYW4ndCBnZXQgYW55IHVzZWZ1bCBpbmZvcm1hdGlvbiBvdXQgb2YgdGhlIGdyYXBocwoKYGBge3J9CmFuaW1hbF9jb21wbGFpbnRzICU+JSAKICBncm91cF9ieShzdWJ1cmIpICU+JSAKICBjb3VudChzb3J0ID0gVFJVRSkKCiMgbGV0J3MgZHJvcCBhbnkgc3VidXJicyB3aXRoIGxlc3MgdGhhbiAyMDAgY2FzZXMKCmFuaW1hbF9jb21wbGFpbnRzICU+JSAKICBncm91cF9ieShzdWJ1cmIpICU+JSAKICBzdW1tYXJpc2UoY291bnQgPSBuKCksIGFuaW1hbF90eXBlKSAlPiUgCiAgZmlsdGVyKGNvdW50ID49IDUwMCkgJT4lIAogIGdncGxvdChhZXMoeCA9IHN1YnVyYiwgeSA9IGNvdW50LCBmaWxsID0gYW5pbWFsX3R5cGUpKSArCiAgZ2VvbV9jb2woKSArCiAgY29vcmRfZmxpcCgpCmBgYAoKVGhlIGhpZ2hlc3QgY291bnQgYnkgcXVpdGUgYSBsYXJnZSBtYXJnaW4gaXMgdW5hbGxvY2F0ZWQgdG8gYSBzcGVjaWZpYyBzdWJ1cmIuCgpgYGB7cn0KYW5pbWFsX2NvbXBsYWludHMgJT4lIAogIGdyb3VwX2J5KHN1YnVyYikgJT4lIAogIHN1bW1hcmlzZShjb3VudCA9IG4oKSwgYW5pbWFsX3R5cGUpICU+JSAKICBmaWx0ZXIoY291bnQgPj0gNTAwKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gc3VidXJiLCB5ID0gY291bnQsIGZpbGwgPSBhbmltYWxfdHlwZSkpICsKICBnZW9tX2NvbChwb3NpdGlvbiA9ICJmaWxsIikgKwogIGNvb3JkX2ZsaXAoKSAKYGBgCkF0IGEgZ2xhbmNlLCB0aGVyZSdzIG5vIGJpZyBkaWZmZXJlbmNlIG9uIGFuaW1hbCB0eXBlcy4gQWxsIHRoZSBzdWJ1cmJzIGhhdmUgYSBsYXJnZSBtYWpvcml0eSBvZiBkb2dzLiBDb3VsZCB3ZSBkbyBhIGh5cG90aGVzaXMgdGVzdCB0byBzZWUgaWYgdGhlcmUgaXMgYSBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50IGRpZmZlcmVuY2U/CgpgYGB7cn0KYW5pbWFsX2NvbXBsYWludHMgJT4lIAogIGdyb3VwX2J5KHN1YnVyYikgJT4lIAogIHN1bW1hcmlzZShjb3VudCA9IG4oKSwgYW5pbWFsX3R5cGUpICU+JSAKICBmaWx0ZXIoY291bnQgPCA1MDAgJiBjb3VudCA+IDEwMCkgJT4lIAogIGdncGxvdChhZXMoeCA9IHN1YnVyYiwgeSA9IGNvdW50LCBmaWxsID0gYW5pbWFsX3R5cGUpKSArCiAgZ2VvbV9jb2wocG9zaXRpb24gPSAiZmlsbCIpICsKICBjb29yZF9mbGlwKCkgCmBgYApMb29raW5nIGF0IHRoZSBsb3dlciBlbmQgb2YgdGhlIHBvcHVsYXRpb24sIHdlIHNlZSBhbiBvdXRsaWVyLiBUb3duc3ZpbGxlIENpdHkgaGFzIHdheSBtb3JlIGNhdHMgdGhhbiBhbnkgb2YgdGhlIG90aGVyIHN1YnVyYnMuIEluIGZhY3QsIGl0J3MgYWxtb3N0IDUwLzUwIQoKTm93IHN0aWxsIGxvb2tpbmcgYXQgdGhlIFRvd25zdmlsbGUgZGF0YXNldCwgd2UnbGwgYnJlYWsgaXQgZG93biBieSBjb21wbGFpbnQgdHlwZToKYGBge3J9CmFuaW1hbF9jb21wbGFpbnRzICU+JSAKICBncm91cF9ieShzdWJ1cmIpICU+JSAKICBzdW1tYXJpc2UoY291bnQgPSBuKCksIGNvbXBsYWludF90eXBlKSAlPiUgCiAgZmlsdGVyKGNvdW50ID49IDUwMCAmIGNvdW50IDw9IDQwMDApICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBzdWJ1cmIsIHkgPSBjb3VudCwgZmlsbCA9IGNvbXBsYWludF90eXBlKSkgKwogIGdlb21fY29sKHBvc2l0aW9uID0gImZpbGwiKSArCiAgY29vcmRfZmxpcCgpIApgYGAKCk5vdyBmb3IgdGhlIGxvd2VyIGVuZCBvZiB0aGUgY291bnQ6CmBgYHtyfQphbmltYWxfY29tcGxhaW50cyAlPiUgCiAgZ3JvdXBfYnkoc3VidXJiKSAlPiUgCiAgc3VtbWFyaXNlKGNvdW50ID0gbigpLCBjb21wbGFpbnRfdHlwZSkgJT4lIAogIGZpbHRlcihjb3VudCA8IDUwMCAmIGNvdW50ID4gNTApICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBzdWJ1cmIsIHkgPSBjb3VudCwgZmlsbCA9IGNvbXBsYWludF90eXBlKSkgKwogIGdlb21fY29sKHBvc2l0aW9uID0gImZpbGwiKSArCiAgY29vcmRfZmxpcCgpIApgYGAKCkknbSBub3Qgc3VyZSBtdWNoIGNhbiBiZSBnbGVhbWVkIHdpdGggc28gbWFueSBjb21wbGFpbnRfdHlwZXMuIExldCdzIHRyeSBmb2N1c2luZyBtb3JlIHNwZWNpZmljYWxseS4KCk9uZSB0aGluZyB0byBub3RlIGhlcmUsIGlzIHRoZSB2YXN0IHZhcmlhdGlvbiBpbiB0b2xlcmFuY2UgZm9yIG5vaXNlLiBNb3N0IGNhdGVnb3JpZXMgYXJlIGNvbnNpc3RlbnQgZXhjZXB0IHRoaXMgb25lLiBDbHVkZW4gZm9yIGV4YW1wbGUgaGFzIGEgc21hbGwgcGVyY2VudGFnZSBvZiBub2lzZSBjb21wbGFpbnRzLHdoaWxlIEJvaGxlIFBsYWlucyBoYXMgYSBodWdlIHBlcmNlbnRhZ2UuIFRoaXMgcmVxdWlyZXMgbW9yZSBpbnZlc3RpZ2F0aW9uIHRvIGZpZ3VyZSBvdXQgdGhlIHJvb3QgY2F1c2Ugb2YgdGhpczogCgpgYGB7cn0KYW5pbWFsX2NvbXBsYWludHMgJT4lIAogIGdyb3VwX2J5KHN1YnVyYikgJT4lIAogIHN1bW1hcmlzZShjb3VudCA9IG4oKSwgY29tcGxhaW50X3R5cGUpICU+JSAKICBmaWx0ZXIoY291bnQgPj0gNTAwKSAlPiUgCiAgZmlsdGVyKGNvbXBsYWludF90eXBlID09ICJOb2lzZSIgfCAoY29tcGxhaW50X3R5cGUgPT0gIkF0dGFjayIpKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gc3VidXJiLCB5ID0gY291bnQsIGZpbGwgPSBjb21wbGFpbnRfdHlwZSkpICsKICBnZW9tX2NvbChwb3NpdGlvbiA9ICJmaWxsIikgKwogIGNvb3JkX2ZsaXAoKSAKCmFuaW1hbF9jb21wbGFpbnRzICU+JSAKICBncm91cF9ieShzdWJ1cmIpICU+JSAKICBzdW1tYXJpc2UoY291bnQgPSBuKCksIGNvbXBsYWludF90eXBlKSAlPiUgCiAgZmlsdGVyKGNvdW50ID49IDUwMCkgJT4lIAogIGZpbHRlcihjb21wbGFpbnRfdHlwZSA9PSAiTm9pc2UiIHwgKGNvbXBsYWludF90eXBlID09ICJBZ2dyZXNzaXZlIEFuaW1hbCIpKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gc3VidXJiLCB5ID0gY291bnQsIGZpbGwgPSBjb21wbGFpbnRfdHlwZSkpICsKICBnZW9tX2NvbChwb3NpdGlvbiA9ICJmaWxsIikgKwogIGNvb3JkX2ZsaXAoKSAKCmFuaW1hbF9jb21wbGFpbnRzICU+JSAKICBncm91cF9ieShzdWJ1cmIpICU+JSAKICBzdW1tYXJpc2UoY291bnQgPSBuKCksIGNvbXBsYWludF90eXBlKSAlPiUgCiAgZmlsdGVyKGNvdW50ID49IDUwMCkgJT4lIAogIGZpbHRlcihjb21wbGFpbnRfdHlwZSA9PSAiV2FuZGVyaW5nIiB8IChjb21wbGFpbnRfdHlwZSA9PSAiQWdncmVzc2l2ZSBBbmltYWwiKSkgJT4lIAogIGdncGxvdChhZXMoeCA9IHN1YnVyYiwgeSA9IGNvdW50LCBmaWxsID0gY29tcGxhaW50X3R5cGUpKSArCiAgZ2VvbV9jb2wocG9zaXRpb24gPSAiZmlsbCIpICsKICBjb29yZF9mbGlwKCkgCgphbmltYWxfY29tcGxhaW50cyAlPiUgCiAgZ3JvdXBfYnkoc3VidXJiKSAlPiUgCiAgc3VtbWFyaXNlKGNvdW50ID0gbigpLCBjb21wbGFpbnRfdHlwZSkgJT4lIAogIGZpbHRlcihjb3VudCA+PSA1MDApICU+JSAKICBmaWx0ZXIoY29tcGxhaW50X3R5cGUgPT0gIkVuY2xvc3VyZSIgfCAoY29tcGxhaW50X3R5cGUgPT0gIk5vaXNlIikpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBzdWJ1cmIsIHkgPSBjb3VudCwgZmlsbCA9IGNvbXBsYWludF90eXBlKSkgKwogIGdlb21fY29sKHBvc2l0aW9uID0gImZpbGwiKSArCiAgY29vcmRfZmxpcCgpIApgYGAKCkZvciB0aGUgbGVzcyB0aGFuIDUwMCBncmVhdGVyIHRoYW4gNTAgZ3JvdXBzOgpgYGB7cn0KYW5pbWFsX2NvbXBsYWludHMgJT4lIAogIGdyb3VwX2J5KHN1YnVyYikgJT4lIAogIHN1bW1hcmlzZShjb3VudCA9IG4oKSwgY29tcGxhaW50X3R5cGUpICU+JSAKICBmaWx0ZXIoY291bnQgPCA1MDAgJiBjb3VudCA+IDEwMCkgJT4lIAogIGZpbHRlcihjb21wbGFpbnRfdHlwZSA9PSAiTm9pc2UiIHwgKGNvbXBsYWludF90eXBlID09ICJBdHRhY2siKSkgJT4lIAogIGdncGxvdChhZXMoeCA9IHN1YnVyYiwgeSA9IGNvdW50LCBmaWxsID0gY29tcGxhaW50X3R5cGUpKSArCiAgZ2VvbV9jb2wocG9zaXRpb24gPSAiZmlsbCIpICsKICBjb29yZF9mbGlwKCkgCgphbmltYWxfY29tcGxhaW50cyAlPiUgCiAgZ3JvdXBfYnkoc3VidXJiKSAlPiUgCiAgc3VtbWFyaXNlKGNvdW50ID0gbigpLCBjb21wbGFpbnRfdHlwZSkgJT4lIAogIGZpbHRlcihjb3VudCA8IDUwMCAmIGNvdW50ID4gMTAwKSAlPiUgIAogIGZpbHRlcihjb21wbGFpbnRfdHlwZSA9PSAiTm9pc2UiIHwgKGNvbXBsYWludF90eXBlID09ICJBZ2dyZXNzaXZlIEFuaW1hbCIpKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gc3VidXJiLCB5ID0gY291bnQsIGZpbGwgPSBjb21wbGFpbnRfdHlwZSkpICsKICBnZW9tX2NvbChwb3NpdGlvbiA9ICJmaWxsIikgKwogIGNvb3JkX2ZsaXAoKSAKCmFuaW1hbF9jb21wbGFpbnRzICU+JSAKICBncm91cF9ieShzdWJ1cmIpICU+JSAKICBzdW1tYXJpc2UoY291bnQgPSBuKCksIGNvbXBsYWludF90eXBlKSAlPiUgCiAgZmlsdGVyKGNvdW50IDwgNTAwICYgY291bnQgPiAxMDApICU+JSAKICBmaWx0ZXIoY29tcGxhaW50X3R5cGUgPT0gIldhbmRlcmluZyIgfCAoY29tcGxhaW50X3R5cGUgPT0gIkFnZ3Jlc3NpdmUgQW5pbWFsIikpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBzdWJ1cmIsIHkgPSBjb3VudCwgZmlsbCA9IGNvbXBsYWludF90eXBlKSkgKwogIGdlb21fY29sKHBvc2l0aW9uID0gImZpbGwiKSArCiAgY29vcmRfZmxpcCgpIAoKYW5pbWFsX2NvbXBsYWludHMgJT4lIAogIGdyb3VwX2J5KHN1YnVyYikgJT4lIAogIHN1bW1hcmlzZShjb3VudCA9IG4oKSwgY29tcGxhaW50X3R5cGUpICU+JSAKICBmaWx0ZXIoY291bnQgPCA1MDAgJiBjb3VudCA+IDEwMCkgJT4lIAogICNmaWx0ZXIoY29tcGxhaW50X3R5cGUgPT0gIkVuY2xvc3VyZSIgfCAoY29tcGxhaW50X3R5cGUgPT0gIk5vaXNlIikpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBzdWJ1cmIsIHkgPSBjb3VudCwgZmlsbCA9IGNvbXBsYWludF90eXBlKSkgKwogIGdlb21fY29sKHBvc2l0aW9uID0gImZpbGwiKSArCiAgY29vcmRfZmxpcCgpICsKICBmYWNldF93cmFwKH4gc3VidXJiKQpgYGAKCgpgYGB7cn0KYW5pbWFsX2NvbXBsYWludHMgJT4lIAogIGdyb3VwX2J5KHN1YnVyYikgJT4lIAogIHN1bW1hcmlzZShjb3VudCA9IG4oKSwgY29tcGxhaW50X3R5cGUsIGFuaW1hbF90eXBlKSAlPiUgCiAgZmlsdGVyKGNvdW50IDwgNTAwICYgY291bnQgPiAxMDApICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBjb21wbGFpbnRfdHlwZSwgeSA9IGNvdW50LCBmaWxsID0gY29tcGxhaW50X3R5cGUpKSArCiAgZ2VvbV9jb2woKSArCiAgZmFjZXRfd3JhcCh+IHN1YnVyYikKYGBgCgpGcm9tIHRoaXMgZ3JhcGgsIHdlIGNhbiBzZWUgdGhhdCBIeWRlIFBhcmsgaGFzIGEgZGlzcHJvcG9ydGlvbmF0ZSBhbW91bnQgb2YgcHJpdmF0ZSBpbXBvdW5kcywgd2hpbGUgQm9obGUgcGxhaW5zIGhhcyBtb3JlIG5vaXNlIGNvbXBsYWludHMuCgpQb3RlbnRpYWwgaHlwb3RoZXNpcyB0ZXN0OgoKVGhhdCB0aGUgbGV2ZWwgb2YgcHJpdmF0ZSBpbXBvdW5kcyBpbiBIeWRlIFBhcmsgYmVpbmcgZ3JlYXRlciBpcyBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50LgoKVGhhdCB0aGUgbGV2ZWwgb2Ygbm9pc2UgaW4gQm9obGUgUGxhaW5zIGJlaW5nIGdyZWF0ZXIgaXMgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudC4KYGBge3J9CmFuaW1hbF9jb21wbGFpbnRzICU+JSAKICBncm91cF9ieShzdWJ1cmIpICU+JSAKICBjb3VudCgpICU+JSAKICBmaWx0ZXIobiA8IDUwMCAmIG4gPiAxMDApCmBgYAoKCgoKCgpMZXQncyBsb29rIGF0IHRoZSBzdWJ1cmJzIHdpdGggbXVjaCBoaWdoZXIgY29tcGxhaW50cyBub3c6CgpgYGB7cn0KYW5pbWFsX2NvbXBsYWludHMgJT4lIAogIGdyb3VwX2J5KHN1YnVyYikgJT4lIAogIHN1bW1hcmlzZShjb3VudCA9IG4oKSwgY29tcGxhaW50X3R5cGUsIGFuaW1hbF90eXBlKSAlPiUgCiAgZmlsdGVyKGNvdW50ID49IDUwMCAmIGNvdW50IDw0MDAwKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gY29tcGxhaW50X3R5cGUsIHkgPSBjb3VudCwgZmlsbCA9IGNvbXBsYWludF90eXBlKSkgKwogIGdlb21fY29sKCkgKwogIGZhY2V0X3dyYXAofiBzdWJ1cmIpCmBgYAoKCgoKCiMjIyAyLiBhKSBBcmUgdGhlcmUgYW55IG1ham9yIGRpZmZlcmVuY2VzIGJldHdlZW4gcmVnaW9ucz8KCmIpIEhvdyBkbyB0aGUgYW5pbWFsIG91dGNvbWVzIGRpZmZlciBvdmVyIHRpbWU/CgpjKSBBcmUgdGhlcmUgYW55IG5vdGljZWFibGUgYW5vbWFsaWVzIGluIHRoZSBkYXRhPwoKCkl0J3MgaW1wb3NzaWJsZSB0byBzYXkgaWYgdGhlcmUncyBkaWZmZXJlbnQgcGVha3Mgb2YgdGltZXMgb2YgeWVyIHBlciByZWdpb24sIGFzIHdlIG9ubHkgaGF2ZSB0aGUgZGF0YSBmb3IgdGhlIHllYXIgYXMgYSB3aG9sZS4gVW5sZXNzIHdlIGxvb2sgYXQgU3VidXJiIHJhdGhlciB0aGFuIHJlZ2lvbiwgYW5kIGJyZWFrIHRoaXMgZG93biBieSB0aW1lLiBIb3dldmVyLCBJIHRoaW5rIGl0J2QgYmUgZ29vZCB0byB1c2UgdGhlIGdlbmVyYWwgQXV0cmFsaWEgKG5hdGlvbndpZGUpIGRhdGEuCgoKUHJvcG9ydGlvbnMgb3ZlcmFsbCBieSByZWdpb24gYW5kIGJ5IG91dGNvbWUuIFdlIGNhbiBzZWUgdGhhdCBpbiBnZW5lcmFsLCByZWdpb25zIGhhdmUgcHJldHR5IHNpbWlsYXIgcHJvcG9ydGlvbnMgYWNyb3NzIGFsbCBvdXRjb21lcy4gVGhpcyB3b24ndCBiZSB0aGUgY2FzZSBmb3IgZXZlcnkgeWVhciB0aG91Z2ggYW5kIHRyZW5kcyBvdmVyIHRpbWUsIHRoYXQncyB0aGUgbW9yZSBpbnRlcmVzdGluZyBzdHVmZi4KYGBge3IsIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGVycm9yPUZBTFNFLCBldmFsPVRSVUV9CmFuaW1hbF9vdXRjb21lcyAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gcmVnaW9uLCB5ID0gbnVtYmVyX29mX29jY3VyZW5jZXMsIGZpbGwgPSBvdXRjb21lLCBjb2wgPSBvdXRjb21lKSkgKwogIGdlb21fY29sKHBvc2l0aW9uID0gImZpbGwiKQpgYGAKClRoaXMgaXMgdGhlIHNhbWUgdGhpbmcgYXMgYmVmb3JlLCBidXQgZm9yIGFuaW1hbCB0eXBlLiBTYW1lIGFzIGJlZm9yZSwgbm90IG11Y2ggZGlzY2VybmlibGUgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSByZWdpb25zLgpgYGB7ciwgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgZXJyb3I9RkFMU0UsIGV2YWw9VFJVRX0KYW5pbWFsX291dGNvbWVzICU+JSAKICBnZ3Bsb3QoYWVzKHggPSByZWdpb24sIHkgPSBudW1iZXJfb2Zfb2NjdXJlbmNlcywgZmlsbCA9IGFuaW1hbF90eXBlLCBjb2wgPSBhbmltYWxfdHlwZSkpICsKICBnZW9tX2NvbChwb3NpdGlvbiA9ICJmaWxsIikKYGBgCgoKCgpOZXh0IGlzIGp1c3QgdGhlIHN1bSBvY3VycmVuY2VzLiBXZSBjYW4gc2VlIHRoZSByZWdpb25zIHRoYXQgaGF2ZSB3YXkgbW9yZSBhbmltYWxzIGluanVyZWQvdGFrZW4gaW4gYnkgdGhlIFJTUENBLiBUaGlzIGNvdWxkIGJlIGEgcG9wdWxhdGlvbiB0aGluZywgbWF5YmUgdGhlc2UgcmVnaW9ucyBqdXN0IGhhdmUgbW9yZSB3aWxkbGlmZSBwb3B1bGF0aW9ucyBldGMuLCBvciBldmVuIGEgYmlnZ2VyIFJTUENBIHByZXNlbmNlIGxlYWRpbmcgdG8gbW9yZSBjYXNlcy4KYGBge3IsIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGVycm9yPUZBTFNFLCBldmFsPVRSVUV9CmFuaW1hbF9vdXRjb21lcyAlPiUgCiAgZ3JvdXBfYnkocmVnaW9uKSAlPiUgCiAgc3VtbWFyaXNlKHN1bV9vZl9vY2N1cmVuY2VzID0gc3VtKG51bWJlcl9vZl9vY2N1cmVuY2VzLCBuYS5ybSA9IFRSVUUpKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gcmVnaW9uLCB5ID0gc3VtX29mX29jY3VyZW5jZXMpKSArCiAgZ2VvbV9jb2woY29sID0gImJsdWUiLCBmaWxsID0gImJsdWUiKQpgYGAKCgoKU28sIHRoaXMgaXMgdGhlIGRhdGEgYWNyb3NzIHRpbWUgKGZyb20gMTk5OS0yMDE4KSwgd2l0aCB0aW1lIG9uIHRoZSB4LWF4aXMgYW5kIG51bWJlciBvZiBvY2N1cmVuY2VzIG9uIHRoZSB5LiBGYWNldGVkIGludG8gZ3JhcGhzIGJhc2VkIG9uIG91dGNvbWUsIHdpdGggdGhlIGNvbG91cmVkIGxpbmVzIHJlcHJlc2VudGluZyBkaWZmZXJlbnQgcmVnaW9ucy4KYGBge3IsIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGVycm9yPUZBTFNFLCBldmFsPVRSVUV9CmFuaW1hbF9vdXRjb21lcyAlPiUgCiAgZHJvcF9uYSgpICU+JSAKICBncm91cF9ieShyZWdpb24sIG91dGNvbWUsIHllYXIpICU+JQogIHN1bW1hcml6ZSh0b3RhbF9pbmp1cmllcyA9IHN1bShudW1iZXJfb2Zfb2NjdXJlbmNlcykpICU+JQogIHVuZ3JvdXAoKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0geWVhciwgeSA9IHRvdGFsX2luanVyaWVzLCBjb2xvciA9IHJlZ2lvbikpICsKICBnZW9tX2xpbmUoKSArCiAgZmFjZXRfd3JhcCh+b3V0Y29tZSwgc2NhbGVzID0gImZyZWVfeSIpICsKICBsYWJzKHggPSAiRGF0ZSIsIHkgPSAiTnVtYmVyIG9mIGluanVyaWVzIiwgY29sb3IgPSAiUmVnaW9uIikKCmBgYAoKV2hhdCBjYW4gd2Ugc2F5IGFib3V0IHRoaXM/IFdlbGwsIFFMRCBoYXMgaGFkIHRoZWlyIHRyYW5zZmVycyBnbyB3YXkgdXAgc2luY2UgYWJvdXQgMjAwOSwgYW5kIGluIGdlbmVyYWwgbG9va3MgbGlrZSBhbiBpbmNyZWFzZSBpbiBjYXNlcyBmb3IgdGhlbS4gTlNXIGhhZCBhIGJpZyBzcGlrZSBvZiBDdXJyZW50bHkgSW4gQ2FyZSBhcm91bmQgMjAwNC4gRXV0aGFuaXNhdGlvbiBpbiBnZW5lcmFsIHNlZW1zIHRvIGJlIGZhbGxpbmcgb3V0IG9mIGZhdm91ciAod2hpY2ggaXMgYWN0dWFsbHkgdHJ1ZSwgdGhlIFJTUENBIHRyaWVzIHRvIGRvIGl0IGxlc3MgZm9yIHZhcmlvdXMgcmVhc29ucywgb25lIGFjdHVhbGx5IGJlaW5nIHRoZSBtZW50YWwgaGVhbHRoIG9mIHRoZSBzdGFmZiBhbmQgYW5vdGhlciBiZWluZyBsb3RzIG9mIGV1dGhhbmlzYXRpb25zIGxlYWRzIHRvIGEgbmVnYXRpdmUgcGVyY2VwdGlvbiBvZiBhbmltYWwgc2hlbHRlcnMpCgoKCgpFeGFjdCBzYW1lIGFzIGJlZm9yZSwgYnV0IGZhY2V0ZWQgb24gYW5pbWFsIHR5cGUgcmF0aGVyIHRoYW4gb3V0Y29tZS4KYGBge3IsIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGVycm9yPUZBTFNFLCBldmFsPVRSVUV9CmFuaW1hbF9vdXRjb21lcyAlPiUgCiAgZHJvcF9uYSgpICU+JSAKICBncm91cF9ieShyZWdpb24sIGFuaW1hbF90eXBlLCB5ZWFyKSAlPiUKICBzdW1tYXJpemUodG90YWxfaW5qdXJpZXMgPSBzdW0obnVtYmVyX29mX29jY3VyZW5jZXMpKSAlPiUKICB1bmdyb3VwKCkgJT4lIAogIGdncGxvdChhZXMoeCA9IHllYXIsIHkgPSB0b3RhbF9pbmp1cmllcywgY29sb3IgPSByZWdpb24pKSArCiAgZ2VvbV9saW5lKCkgKwogIGZhY2V0X3dyYXAofmFuaW1hbF90eXBlLCBzY2FsZXMgPSAiZnJlZV95IikgKwogIGxhYnMoeCA9ICJEYXRlIiwgeSA9ICJOdW1iZXIgb2YgaW5qdXJpZXMiLCBjb2xvciA9ICJSZWdpb24iKQpgYGAKClFMRCBoYXMgaGFkIGEgbG90IG1vcmUgd2lsZGxpZmUgY2FzZXMsIHN0ZWFkaWx5IGNsaW1iaW5nIHNpbmNlIGFib3V0IDIwMDYuIE5TVyBoYXMgaGFkIGEgYmlnIGRyb3AgaW4gY2F0cyByZWNlbnRseS4gRG9ncyB0b28uIEhvcnNlcyBoYXZlIGdvbmUgdXAgZXZlcnkgcmVnaW9uIGl0IGxvb2tzIGxpa2UuIE5UIGhhcyBoYWQgYSBodWdlIHNwaWtlIGluIGNhdHMgZnJvbSAyMDE1LTIwMTYuCgoKCgoKVGhpcyBvbmUgaGFzIHRoZSBzYW1lIHggYW5kIHksIGJ1dCBpcyBmYWNldGVkIGJhc2VkIG9uIHJlZ2lvbi4gVGhlIGNvbG91cmVkIGxpbmVzIG5vdyByZXByZXNlbnQgdGhlIG91dGNvbWVzLgpgYGB7ciwgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgZXJyb3I9RkFMU0UsIGV2YWw9VFJVRX0KYW5pbWFsX291dGNvbWVzICU+JSAKICBkcm9wX25hKCkgJT4lIAogIGdyb3VwX2J5KHJlZ2lvbiwgb3V0Y29tZSwgeWVhcikgJT4lCiAgc3VtbWFyaXplKHRvdGFsX2luanVyaWVzID0gc3VtKG51bWJlcl9vZl9vY2N1cmVuY2VzKSkgJT4lCiAgdW5ncm91cCgpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSB5ZWFyLCB5ID0gdG90YWxfaW5qdXJpZXMsIGNvbG9yID0gb3V0Y29tZSkpICsKICBnZW9tX2xpbmUoKSArCiAgZmFjZXRfd3JhcCh+cmVnaW9uLCBzY2FsZXMgPSAiZnJlZV95IikgKwogIGxhYnMoeCA9ICJEYXRlIiwgeSA9ICJOdW1iZXIgb2YgaW5qdXJpZXMiLCBjb2xvciA9ICJPdXRjb21lIikKYGBgCgpXQSBpbiAyMDA2IGhhZCBhIGJpZyBpbmNyZWFzZSBpbiBldXRoYW5pemF0aW9ucy4gVklDIGhhcyBoYWQgdGhlaXJzIHN0ZWFkaWx5IGRlY3JlYXNpbmcgb3ZlciB0aW1lLCB0aGlzIGlzIHJlZmxlY3RlZCBhbHNvIGluIE5TVywgVEFTIGFuZCBBQ1QuCgoKCgoKU2FtZSBhcyBiZWZvcmUgd2l0aCBmYWNldGluZyBiYXNlZCBvbiByZWdpb24sIGJ1dCBub3cgdGhlIGNvbG91cmVkIGxpbmVzIHJlcHJlc2VudCB0aGUgdHlwZSBvZiBhbmltYWwgdGhlIFJTUENBIGlzIGRlYWxpbmcgd2l0aC4KYGBge3IsIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGVycm9yPUZBTFNFLCBldmFsPVRSVUV9CmFuaW1hbF9vdXRjb21lcyAlPiUgCiAgZHJvcF9uYSgpICU+JSAKICBncm91cF9ieShyZWdpb24sIGFuaW1hbF90eXBlLCB5ZWFyKSAlPiUKICBzdW1tYXJpemUodG90YWxfaW5qdXJpZXMgPSBzdW0obnVtYmVyX29mX29jY3VyZW5jZXMpKSAlPiUKICB1bmdyb3VwKCkgJT4lIAogIGdncGxvdChhZXMoeCA9IHllYXIsIHkgPSB0b3RhbF9pbmp1cmllcywgY29sb3IgPSBhbmltYWxfdHlwZSkpICsKICBnZW9tX2xpbmUoKSArCiAgZmFjZXRfd3JhcCh+cmVnaW9uLCBzY2FsZXMgPSAiZnJlZV95IikgKwogIGxhYnMoeCA9ICJEYXRlIiwgeSA9ICJOdW1iZXIgb2YgaW5qdXJpZXMiLCBjb2xvciA9ICJBbmltYWwgVHlwZSIpCmBgYAoKTlQgaGFzIGhhZCBhIGJpZyBzcGlrZSBpbiBkb2dzIGFuZCBjYXRzIGluIHJlY2VudCB5ZWFycy4gV0EgaGFkIGEgYmlnIHNwaWtlIGluIHdpbGRsaWZlIGluIDIwMDUsIGNvcnJlc3BvbmRpbmcgd2l0aCB0aGVpciBzcGlrZSBpbiBldXRoYW5pemF0aW9ucyAtIGNvbW1vbiBzZW5zZSBhbmQgZG9tYWluIGtub3dsZWRnZSB0ZWxsIHVzIHRoZXNlIGFyZSBsaWtlbHkgaGlnaGx5IGNvcnJlbGF0ZWQuIFZJQydzIG51bWJlcnMgaW4gZ2VuZXJhbCBzZWVtIHRvIGJlIGRlY3JlYXNpbmcgb3ZlciB0aW1lLgoKCgoKTG9va2luZyBub3cgc3BlY2lmaWNhbGx5IGF0IGV1dGhhbml6YXRpb25zLCBmYWNldGVkIGJ5IHJlZ2lvbiB3aXRoIHRoZSBsaW5lcyByZXByZXNlbnRpbmcgZXV0aGFuaXphdGlvbnMuCmBgYHtyLCBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBlcnJvcj1GQUxTRSwgZXZhbD1UUlVFfQphbmltYWxfb3V0Y29tZXMgJT4lIAogIGRyb3BfbmEoKSAlPiUgCiAgZ3JvdXBfYnkocmVnaW9uLCBvdXRjb21lLCB5ZWFyKSAlPiUKICBzdW1tYXJpemUodG90YWxfaW5qdXJpZXMgPSBzdW0obnVtYmVyX29mX29jY3VyZW5jZXMpKSAlPiUKICB1bmdyb3VwKCkgJT4lIAogIGZpbHRlcihvdXRjb21lID09ICJFdXRoYW5pemVkIikgJT4lIAogIGdncGxvdChhZXMoeCA9IHllYXIsIHkgPSB0b3RhbF9pbmp1cmllcywgY29sb3IgPSBvdXRjb21lKSkgKwogIGdlb21fbGluZSgpICsKICBmYWNldF93cmFwKH5yZWdpb24sIHNjYWxlcyA9ICJmcmVlX3kiKSArCiAgbGFicyh4ID0gIkRhdGUiLCB5ID0gIk51bWJlciBvZiBpbmp1cmllcyIsIGNvbG9yID0gIk91dGNvbWUiKQpgYGAKCgoKTm93IHdlIG5vIGxvbmdlciBmYWNldCBieSByZWdpb24uCmBgYHtyLCBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBlcnJvcj1GQUxTRSwgZXZhbD1UUlVFfQphbmltYWxfb3V0Y29tZXMgJT4lIAogIGRyb3BfbmEoKSAlPiUgCiAgZ3JvdXBfYnkob3V0Y29tZSwgYW5pbWFsX3R5cGUsIHllYXIpICU+JQogIHN1bW1hcml6ZSh0b3RhbF9pbmp1cmllcyA9IHN1bShudW1iZXJfb2Zfb2NjdXJlbmNlcykpICU+JQogIHVuZ3JvdXAoKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0geWVhciwgeSA9IHRvdGFsX2luanVyaWVzLCBjb2xvciA9IGFuaW1hbF90eXBlKSkgKwogIGdlb21fbGluZSgpICsKICBmYWNldF93cmFwKH5vdXRjb21lLCBzY2FsZXMgPSAiZnJlZV95IikgKwogIGxhYnMoeCA9ICJEYXRlIiwgeSA9ICJOdW1iZXIgb2YgaW5qdXJpZXMiLCBjb2xvciA9ICJBbmltYWwgVHlwZSIpCgphbmltYWxfb3V0Y29tZXMgJT4lIAogIGRyb3BfbmEoKSAlPiUgCiAgZ3JvdXBfYnkob3V0Y29tZSwgYW5pbWFsX3R5cGUsIHllYXIpICU+JQogIHN1bW1hcml6ZSh0b3RhbF9pbmp1cmllcyA9IHN1bShudW1iZXJfb2Zfb2NjdXJlbmNlcykpICU+JQogIHVuZ3JvdXAoKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0geWVhciwgeSA9IHRvdGFsX2luanVyaWVzLCBjb2xvciA9IG91dGNvbWUpKSArCiAgZ2VvbV9saW5lKCkgKwogIGZhY2V0X3dyYXAofmFuaW1hbF90eXBlLCBzY2FsZXMgPSAiZnJlZV95IikgKwogIGxhYnMoeCA9ICJEYXRlIiwgeSA9ICJOdW1iZXIgb2YgaW5qdXJpZXMiLCBjb2xvciA9ICJPdXRjb21lIikKYGBgCgoKYGBge3IsIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGVycm9yPUZBTFNFLCBldmFsPVRSVUV9CiMgbG9va2luZyBhdCBvbmx5IGV1dGhhbmFzaWEKYW5pbWFsX291dGNvbWVzICU+JSAKICBkcm9wX25hKCkgJT4lIAogIGdyb3VwX2J5KG91dGNvbWUsIGFuaW1hbF90eXBlLCB5ZWFyKSAlPiUKICBzdW1tYXJpemUodG90YWxfaW5qdXJpZXMgPSBzdW0obnVtYmVyX29mX29jY3VyZW5jZXMpKSAlPiUKICB1bmdyb3VwKCkgJT4lIAogIGZpbHRlcihvdXRjb21lID09ICJFdXRoYW5pemVkIikgJT4lIAogIGdncGxvdChhZXMoeCA9IHllYXIsIHkgPSB0b3RhbF9pbmp1cmllcywgY29sb3IgPSBvdXRjb21lKSkgKwogIGdlb21fbGluZSgpICsKICBmYWNldF93cmFwKH5hbmltYWxfdHlwZSwgc2NhbGVzID0gImZyZWVfeSIpICsKICBsYWJzKHggPSAiRGF0ZSIsIHkgPSAiTnVtYmVyIG9mIGluanVyaWVzIiwgY29sb3IgPSAiT3V0Y29tZSIpCgojIGxvb2tpbmcgYXQgb25seSByZWhvbWVkCmFuaW1hbF9vdXRjb21lcyAlPiUgCiAgZHJvcF9uYSgpICU+JSAKICBncm91cF9ieShvdXRjb21lLCBhbmltYWxfdHlwZSwgeWVhcikgJT4lCiAgc3VtbWFyaXplKHRvdGFsX2luanVyaWVzID0gc3VtKG51bWJlcl9vZl9vY2N1cmVuY2VzKSkgJT4lCiAgdW5ncm91cCgpICU+JSAKICBmaWx0ZXIob3V0Y29tZSA9PSAiUmVob21lZCIpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSB5ZWFyLCB5ID0gdG90YWxfaW5qdXJpZXMsIGNvbG9yID0gb3V0Y29tZSkpICsKICBnZW9tX2xpbmUoKSArCiAgZmFjZXRfd3JhcCh+YW5pbWFsX3R5cGUsIHNjYWxlcyA9ICJmcmVlX3kiKSArCiAgbGFicyh4ID0gIkRhdGUiLCB5ID0gIk51bWJlciBvZiBpbmp1cmllcyIsIGNvbG9yID0gIk91dGNvbWUiKQpgYGAKCk9LIHNvIGNhdHMgYW5kIGRvZ3MgaGF2ZSB3YXkgbGVzcyBldXRoYW5pc2F0aW9ucy4gV2lsZGxpZmUgaGFzIGdvbmUgd2F5IHVwISBIb3JzZXMgYXJlIHRvbyBzbWFsbCBhIHNhbXBsZSB0byBiZSBtZWFuaW5nZnVsLiBPdGhlciBhbmltYWxzIGhhdmUgc3Bpa2VkIHRoZW4gZGVjcmVhc2VkLgoKCgpgYGB7ciwgZWNobz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgZXJyb3I9RkFMU0UsIGV2YWw9VFJVRX0KIyBsb29raW5nIGF0IGJvdGggcmVob21lZCBhbmQgZXV0aGFuaXplZAphbmltYWxfb3V0Y29tZXMgJT4lIAogIGRyb3BfbmEoKSAlPiUgCiAgZ3JvdXBfYnkob3V0Y29tZSwgYW5pbWFsX3R5cGUsIHllYXIpICU+JQogIHN1bW1hcml6ZSh0b3RhbF9pbmp1cmllcyA9IHN1bShudW1iZXJfb2Zfb2NjdXJlbmNlcykpICU+JQogIHVuZ3JvdXAoKSAlPiUgCiAgZmlsdGVyKG91dGNvbWUgPT0gIlJlaG9tZWQiIHwgb3V0Y29tZSA9PSAiRXV0aGFuaXplZCIpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSB5ZWFyLCB5ID0gdG90YWxfaW5qdXJpZXMsIGNvbG9yID0gb3V0Y29tZSkpICsKICBnZW9tX2xpbmUoKSArCiAgZmFjZXRfd3JhcCh+YW5pbWFsX3R5cGUsIHNjYWxlcyA9ICJmcmVlX3kiKSArCiAgbGFicyh4ID0gIkRhdGUiLCB5ID0gIk51bWJlciBvZiBpbmp1cmllcyIsIGNvbG9yID0gIk91dGNvbWUiKQpgYGAKCkxvb2tpbmcgYXQgcmVob21lcyB0byBldXRoYW5pc2F0aW9ucywgd2Ugc2VlIGNhdHMgaGF2ZSBhbiB1cHdhcmQgdHJlbmQgd2l0aCBsZXNzIGV1dGhhbmlzYXRpb25zIGFuZCBtb3JlIHJlaG9tZXMsIHdpdGggZG9ncywgYm90aCBoYXZlIGdvbmUgZG93bi4gUGVyaGFwcyB3aXRoIGRvZ3MgdGhlcmUncyBhIGNvbmZvdW5kaW5nIGZhY3Rvci4gSW4gZmFjdCwgaXQgc2VlbXMgbGlrZSB0aGUgUlNQQ0EgaXMgZGVhbGluZyB3aXRoIGxlc3MgZG9ncyBpbiBnZW5lcmFsLgoKCmBgYHtyLCBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBlcnJvcj1GQUxTRSwgZXZhbD1UUlVFfQojIGxvb2tpbmcgYXQgYm90aCByZWhvbWVkLCByZWNsYWltZWQgYW5kIGV1dGhhbml6ZWQKYW5pbWFsX291dGNvbWVzICU+JSAKICBkcm9wX25hKCkgJT4lIAogIGdyb3VwX2J5KG91dGNvbWUsIGFuaW1hbF90eXBlLCB5ZWFyKSAlPiUKICBzdW1tYXJpemUodG90YWxfaW5qdXJpZXMgPSBzdW0obnVtYmVyX29mX29jY3VyZW5jZXMpKSAlPiUKICB1bmdyb3VwKCkgJT4lIAogIGZpbHRlcihvdXRjb21lID09ICJSZWhvbWVkIiB8IG91dGNvbWUgPT0gIkV1dGhhbml6ZWQiIHwgb3V0Y29tZSA9PSAiUmVjbGFpbWVkIikgJT4lCiAgZ2dwbG90KGFlcyh4ID0geWVhciwgeSA9IHRvdGFsX2luanVyaWVzLCBjb2xvciA9IG91dGNvbWUpKSArCiAgZ2VvbV9saW5lKCkgKwogIGZhY2V0X3dyYXAofmFuaW1hbF90eXBlLCBzY2FsZXMgPSAiZnJlZV95IikgKwogIGxhYnMoeCA9ICJEYXRlIiwgeSA9ICJOdW1iZXIgb2YgaW5qdXJpZXMiLCBjb2xvciA9ICJPdXRjb21lIikKYGBgCgoKYGBge3IsIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGVycm9yPUZBTFNFLCBldmFsPVRSVUV9CmFuaW1hbF9vdXRjb21lcyAlPiUgCiAgZHJvcF9uYSgpICU+JSAKICBncm91cF9ieShvdXRjb21lLCBhbmltYWxfdHlwZSwgeWVhcikgJT4lCiAgc3VtbWFyaXplKHRvdGFsX2luanVyaWVzID0gc3VtKG51bWJlcl9vZl9vY2N1cmVuY2VzKSkgJT4lCiAgdW5ncm91cCgpICU+JSAKICBmaWx0ZXIoYW5pbWFsX3R5cGUgPT0gIldpbGRsaWZlIikgJT4lIAogIGdncGxvdChhZXMoeCA9IHllYXIsIHkgPSB0b3RhbF9pbmp1cmllcywgY29sb3IgPSBvdXRjb21lKSkgKwogIGdlb21fbGluZSgpICsKICBsYWJzKHggPSAiRGF0ZSIsIHkgPSAiTnVtYmVyIG9mIGluanVyaWVzIiwgY29sb3IgPSAiT3V0Y29tZSIsIHRpdGxlID0gIldpbGRsaWZlIikKCmFuaW1hbF9vdXRjb21lcyAlPiUgCiAgZHJvcF9uYSgpICU+JSAKICBncm91cF9ieShvdXRjb21lLCBhbmltYWxfdHlwZSwgeWVhciwgcmVnaW9uKSAlPiUKICBzdW1tYXJpemUodG90YWxfaW5qdXJpZXMgPSBzdW0obnVtYmVyX29mX29jY3VyZW5jZXMpKSAlPiUKICB1bmdyb3VwKCkgJT4lIAogIGZpbHRlcihhbmltYWxfdHlwZSA9PSAiV2lsZGxpZmUiICYgb3V0Y29tZSA9PSAiRXV0aGFuaXplZCIpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSB5ZWFyLCB5ID0gdG90YWxfaW5qdXJpZXMsIGNvbG9yID0gb3V0Y29tZSkpICsKICBnZW9tX2xpbmUoKSArCiAgZmFjZXRfd3JhcCh+cmVnaW9uLCBzY2FsZXMgPSAiZnJlZV95IikgKwogIGxhYnMoeCA9ICJEYXRlIiwgeSA9ICJOdW1iZXIgb2YgaW5qdXJpZXMiLCBjb2xvciA9ICJPdXRjb21lIiwgdGl0bGUgPSAiV2lsZGxpZmUiKQpgYGAKCkV1dGhhbml6YXRpb25zIGZvciB3aWxkbGlmZSBoYXZlIG92ZXJhbGwgZ29uZSB1cC4gUXVlZW5zbGFuZCBpcyBza2V3aW5nIHRoZSBkYXRhLCB0aGV5J3ZlIGV1dGhhbml6ZWQgd2F5IG1vcmUhIElzIHRoaXMgbmVjZXNzYXJpbHkgYSBiYWQgdGhpbmc/IEl0IGNvdWxkIGluZGljYXRlIGEgYmlnZ2VyIFJTUENBIHByZXNlbmNlIGluIHRoZSBhcmVhLCBhbmQgbW9yZSB2aWdpbGFuY2UgaW4gcmVnYXJkcyB0byBjb250cm9sbGluZyB0aGUgd2lsZGxpZmUuIAoKCgoKR2VuZXJhbCB0aG91Z2h0czoKCmJpZyBjaGFuZ2UgaW4gMjAwNiBmb3IgV0E7IGN5Y2xvbmUgRW1tYSBNYXJjaCAyMDA2IGNvdWxkJ3ZlIHJlbGVhc2VkIG1hbnkgd2lsZCBhbmltYWxzIGxlYWRpbmcgdG8gaGlnaCBldXRoYW5pemF0aW9ucyAodGhpcyBmb3IgMi5jKQpkaWZmZXJlbnQgdGVycml0b3JpZXMgaGF2ZSBkaWZmZXJlbnQgYXBwcm9hY2hlczsgCgoKCiMjIyA0LiBCdXNpbmVzcyBJbnRlbGxpZ2VuY2Ug4oCTIHVzaW5nIHRoZSBpbnNpZ2h0cyB5b3UgaGF2ZSBmb3VuZCwgY2FuIHlvdSBwcmVkaWN0IGhvdyB0aGlzIG1pZ2h0IGxvb2sgZm9yIHRoZSB1cGNvbWluZyB5ZWFyPwoKCgoKCgpgYGB7cn0KYW5pbWFsX291dGNvbWVzICU+JSAKICBkcm9wX25hKCkgJT4lIAogIGdyb3VwX2J5KHJlZ2lvbiwgb3V0Y29tZSwgeWVhcikgJT4lCiAgc3VtbWFyaXplKHRvdGFsX2luanVyaWVzID0gc3VtKG51bWJlcl9vZl9vY2N1cmVuY2VzKSkgJT4lCiAgdW5ncm91cCgpICU+JSAKICBmaWx0ZXIob3V0Y29tZSA9PSAiRXV0aGFuaXplZCIpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSB5ZWFyLCB5ID0gdG90YWxfaW5qdXJpZXMsIGNvbG9yID0gb3V0Y29tZSkpICsKICBnZW9tX2xpbmUoKSArCiAgZmFjZXRfd3JhcCh+cmVnaW9uLCBzY2FsZXMgPSAiZnJlZV95IikgKwogIGxhYnMoeCA9ICJEYXRlIiwgeSA9ICJOdW1iZXIgb2YgaW5qdXJpZXMiLCBjb2xvciA9ICJPdXRjb21lIikKYGBgCgoKCgoKCgoKCiMjIyBOZXh0IGF0dGVtcHQgZm9yIGEgbW9kZWwKCkkgd2FudCB0byBwcmVkaWN0IHRoZSB0b3RhbCBjYXNlcyBmb3IgQXVzdHJhbGlhLiBXZSB3b24ndCBicmVhayBpdCBkb3duIGJ5IHJlZ2lvbi4gU28gZmlyc3QsIGxldCdzIGdldCBvdXIgc3VtbWFyeSBzdGF0aXN0aWNzIGFuZCBwdXQgaXQgaW4gYSBuZXcgdmFyaWFibGU6CgpgYGB7cn0KYW5pbWFsX291dGNvbWVzICU+JSAKICBkcm9wX25hKCkgJT4lIAogIGdyb3VwX2J5KG91dGNvbWUsIGFuaW1hbF90eXBlLCB5ZWFyLCByZWdpb24pICU+JQogIHN1bW1hcml6ZSh0b3RhbF9pbmp1cmllcyA9IHN1bShudW1iZXJfb2Zfb2NjdXJlbmNlcykpICU+JQogIHVuZ3JvdXAoKSAlPiUgCiAgZmlsdGVyKGFuaW1hbF90eXBlID09ICJDYXRzIiAmIG91dGNvbWUgPT0gIkV1dGhhbml6ZWQiKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0geWVhciwgeSA9IHRvdGFsX2luanVyaWVzLCBjb2xvciA9IG91dGNvbWUpKSArCiAgZ2VvbV9saW5lKCkgKwogIGZhY2V0X3dyYXAofnJlZ2lvbiwgc2NhbGVzID0gImZyZWVfeSIpICsKICBsYWJzKHggPSAiRGF0ZSIsIHkgPSAiTnVtYmVyIG9mIGluanVyaWVzIiwgY29sb3IgPSAiT3V0Y29tZSIsIHRpdGxlID0gIkNhdHMiKQpgYGAKCgpgYGB7cn0KYW5pbWFsX291dGNvbWVzICU+JSAKICBkcm9wX25hKCkgJT4lIAogIGdyb3VwX2J5KG91dGNvbWUsIGFuaW1hbF90eXBlLCB5ZWFyKSAlPiUKICBzdW1tYXJpemUodG90YWxfaW5qdXJpZXMgPSBzdW0obnVtYmVyX29mX29jY3VyZW5jZXMpKSAlPiUKICB1bmdyb3VwKCkgJT4lIAogIGZpbHRlcihhbmltYWxfdHlwZSA9PSAiQ2F0cyIgJiBvdXRjb21lID09ICJFdXRoYW5pemVkIikgJT4lIAogIGdncGxvdChhZXMoeCA9IHllYXIsIHkgPSB0b3RhbF9pbmp1cmllcywgY29sb3IgPSBvdXRjb21lKSkgKwogIGdlb21fbGluZSgpICsKICAjZmFjZXRfd3JhcCh+cmVnaW9uLCBzY2FsZXMgPSAiZnJlZV95IikgKwogIGxhYnMoeCA9ICJEYXRlIiwgeSA9ICJOdW1iZXIgb2YgaW5qdXJpZXMiLCBjb2xvciA9ICJPdXRjb21lIiwgdGl0bGUgPSAiQ2F0cyIpCmBgYAoKCmBgYHtyfQp3aWxkbGlmZV90c2JsIDwtIGFuaW1hbF9vdXRjb21lcyAlPiUgCiAgZHJvcF9uYSgpICU+JSAKICBmaWx0ZXIoYW5pbWFsX3R5cGUgPT0gIkNhdHMiICYgb3V0Y29tZSA9PSAiRXV0aGFuaXplZCIpICU+JSAKICBncm91cF9ieSh5ZWFyKSAlPiUgCiAgc3VtbWFyaXNlKHRvdGFsX2V1dGggPSBzdW0obnVtYmVyX29mX29jY3VyZW5jZXMpKSAlPiUgCiAgdW5ncm91cCgpICU+JSAKICBhc190c2liYmxlKGtleSA9IHllYXIsIGluZGV4ID0gdG90YWxfZXV0aCkKYGBgCgpgYGB7cn0KbGlicmFyeShmYWJsZSkKCiMgRml0IEFSSU1BIG1vZGVsCndpbGRsaWZlX2FyaW1hIDwtIHdpbGRsaWZlX3RzYmwgJT4lIAogIG1vZGVsKHRvdGFsX2V1dGggPSBBUklNQSh0b3RhbF9ldXRoKSkKYGBgCgpgYGB7cn0KIyBHZW5lcmF0ZSBmb3JlY2FzdHMKCiMgQ29udmVydCBBUklNQSBvYmplY3QgdG8gYSB0c2liYmxlIG9iamVjdAp3aWxkbGlmZV90c2JsIDwtIGFzX3RzaWJibGUod2lsZGxpZmVfYXJpbWEsIGtleSA9IHRvdGFsX2V1dGgsIGluZGV4ID0geWVhcikKCiMgR2VuZXJhdGUgZm9yZWNhc3RzCndpbGRsaWZlX2ZvcmVjYXN0IDwtIHdpbGRsaWZlX3RzYmwgJT4lCiAgbW9kZWwoQVJJTUEodG90YWxfZXV0aCkpICU+JSAKICBmb3JlY2FzdChoID0gMzYpCmBgYAoKCgoKCmBgYHtyfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShmYWJsZSkKbGlicmFyeSh0c2liYmxlKQpsaWJyYXJ5KHRzaWJibGVkYXRhKQojIFdlIGFsc28gbmVlZCB0byB1c2UgdGhlICJ1cmNhIiBwYWNrYWdlIHRvIGJlIGFibGUgdG8gdXNlIHRoZSBBUklNQSBtb2RlbApsaWJyYXJ5KHVyY2EpCmBgYAoKCmBgYHtyfQoKCndpbGRsaWZlX3RzYmwgPC0gYW5pbWFsX291dGNvbWVzICU+JSAKICBkcm9wX25hKCkgJT4lIAogIGZpbHRlcihhbmltYWxfdHlwZSA9PSAiQ2F0cyIgJiBvdXRjb21lID09ICJFdXRoYW5pemVkIikgJT4lIAogIGdyb3VwX2J5KHllYXIpICU+JSAKICBzdW1tYXJpc2UodG90YWxfZXV0aCA9IHN1bShudW1iZXJfb2Zfb2NjdXJlbmNlcykpICU+JSAKICB1bmdyb3VwKCkgJT4lCiAgbXV0YXRlKGRhdGUgPSB5ZWFyICU+JSBhcy5EYXRlKHBhc3RlMCgiLTAxLTAxIikpKSAlPiUgCiAgYXNfdHNpYmJsZShrZXkgPSB5ZWFyLCBpbmRleCA9IGRhdGUpCgp3aWxkbGlmZV9hcmltYSA8LSB3aWxkbGlmZV90c2JsICU+JSAKICBtb2RlbChBUklNQSh0b3RhbF9ldXRoKSkKCndpbGRsaWZlX2ZvcmVjYXN0IDwtIHdpbGRsaWZlX2FyaW1hICU+JSAKICBmb3JlY2FzdChoID0gMzYpCgp3aWxkbGlmZV9mb3JlY2FzdAoKCmBgYAoKYGBge3J9CndpbGRsaWZlX2ZvcmVjYXN0ICU+JSAKICBhdXRvcGxvdCgpICsgCiAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwgbWF4KHdpbGRsaWZlX3RzYmwkdG90YWxfZXV0aCwgbmEucm0gPSBUUlVFKSAqIDEuMikpCgpgYGAKCmBgYHtyfQp3aWxkbGlmZV9mY3N0IDwtIHdpbGRsaWZlX2ZvcmVjYXN0ICU+JSAKICBhc190aWJibGUoKSAlPiUgCiAgc2VsZWN0KHllYXIsIC5tZWFuKSAlPiUgCiAgcmVuYW1lKHRvdGFsX2V1dGggPSAubWVhbikKCndpbGRsaWZlX3RzYmxfZmNzdCA8LSB3aWxkbGlmZV90c2JsICU+JSAKICBiaW5kX3Jvd3Mod2lsZGxpZmVfZmNzdCwgLmlkID0gInNvdXJjZSIpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSB5ZWFyLCB5ID0gdG90YWxfZXV0aCwgY29sb3VyID0gc291cmNlKSkgKwogIGdlb21fbGluZSgpICsKICBsYWJzKHRpdGxlID0gIlRvdGFsIEV1dGhhbml6ZWQgQ2F0cyBpbiBBdXN0aW4gQW5pbWFsIENlbnRlciIsCiAgICAgICBzdWJ0aXRsZSA9ICJIaXN0b3JpY2FsIGRhdGEgYW5kIGZvcmVjYXN0cyIsCiAgICAgICB5ID0gIk51bWJlciBvZiBjYXRzIGV1dGhhbml6ZWQiLAogICAgICAgY29sb3IgPSAiU291cmNlIikgKwogIHRoZW1lX21pbmltYWwoKQoKYGBgCgpgYGB7cn0Kd2lsZGxpZmVfZmNzdF90c2JsIDwtIHdpbGRsaWZlX2Zjc3QgJT4lIAogIGFzX3RzaWJibGUoa2V5ID0geWVhciwgaW5kZXggPSB0b3RhbF9ldXRoKSAlPiUgCiAgc2VsZWN0KHllYXIsIHRvdGFsX2V1dGgsIC5tZWFuKQoKZ2dwbG90KHdpbGRsaWZlX2Zjc3RfdHNibCwgYWVzKHggPSB5ZWFyLCB5ID0gdG90YWxfZXV0aCkpICsKICBnZW9tX2xpbmUoKSArCiAgZ2VvbV9saW5lKGFlcyh5ID0gLm1lYW4pLCBjb2xvciA9ICJibHVlIikgKwogIGxhYnModGl0bGUgPSAiRm9yZWNhc3Qgb2YgRXV0aGFuaXplZCBDYXRzIGluIEF1c3RpbiBBbmltYWwgQ2VudGVyIiwKICAgICAgIHggPSAiWWVhciIsCiAgICAgICB5ID0gIlRvdGFsIEV1dGhhbml6ZWQgQ2F0cyIpICsKICB0aGVtZV9taW5pbWFsKCkKCmBgYAoKYGBge3J9CgojIENyZWF0ZSB0c2liYmxlCndpbGRsaWZlX3RzYmwgPC0gYW5pbWFsX291dGNvbWVzICU+JSAKICBkcm9wX25hKCkgJT4lIAogIGZpbHRlcihhbmltYWxfdHlwZSA9PSAiQ2F0cyIgJiBvdXRjb21lID09ICJFdXRoYW5pemVkIikgJT4lIAogIGdyb3VwX2J5KHllYXIpICU+JSAKICBzdW1tYXJpc2UodG90YWxfZXV0aCA9IHN1bShudW1iZXJfb2Zfb2NjdXJlbmNlcykpICU+JSAKICB1bmdyb3VwKCkgJT4lIAogIGFzX3RzaWJibGUoaW5kZXggPSB5ZWFyKQoKIyBGaXQgQVJJTUEgbW9kZWwKd2lsZGxpZmVfYXJpbWEgPC0gd2lsZGxpZmVfdHNibCAlPiUgCiAgbW9kZWwoQVJJTUEodG90YWxfZXV0aCkpCgojIEdlbmVyYXRlIGZvcmVjYXN0cwp3aWxkbGlmZV9mY3N0IDwtIHdpbGRsaWZlX2FyaW1hICU+JSAKICBmb3JlY2FzdChoID0gMzYpCgojIEFkZCBzb3VyY2UgY29sdW1uIHRvIGZvcmVjYXN0CndpbGRsaWZlX2Zjc3QgJT4lCiAgbXV0YXRlKHNvdXJjZSA9ICJmb3JlY2FzdCIpICU+JQogIHNlbGVjdChzb3VyY2UsIHllYXIsIC5tZWFuKSAlPiUKICBiaW5kX3Jvd3Mod2lsZGxpZmVfdHNibCAlPiUgYXNfdGliYmxlKCkgJT4lIG11dGF0ZShzb3VyY2UgPSAiYWN0dWFsIikpICU+JQogIAogICMgUGxvdCB0aGUgYWN0dWFscyBhbmQgZm9yZWNhc3RzCiAgZ2dwbG90KGFlcyh4ID0geWVhciwgeSA9IC5tZWFuLCBjb2xvciA9IHNvdXJjZSkpICsKICBnZW9tX2xpbmUoKSArCiAgbGFicyh5ID0gIlRvdGFsIEV1dGhhbml6ZWQgQ2F0cyIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiYWN0dWFsIiA9ICJibGFjayIsICJmb3JlY2FzdCIgPSAicmVkIikpICsKICB0aGVtZV9taW5pbWFsKCkKCmBgYAoKYGBge3J9CgojIGNyZWF0ZSB0c2liYmxlCndpbGRsaWZlX3RzYmwgPC0gYW5pbWFsX291dGNvbWVzICU+JSAKICBkcm9wX25hKCkgJT4lIAogIGZpbHRlcihhbmltYWxfdHlwZSA9PSAiQ2F0cyIgJiBvdXRjb21lID09ICJFdXRoYW5pemVkIikgJT4lIAogIGdyb3VwX2J5KHllYXIpICU+JSAKICBzdW1tYXJpc2UodG90YWxfZXV0aCA9IHN1bShudW1iZXJfb2Zfb2NjdXJlbmNlcykpICU+JSAKICB1bmdyb3VwKCkgJT4lIAogIGFzX3RzaWJibGUoaW5kZXggPSB5ZWFyKQoKIyBmaWxsIGdhcHMKd2lsZGxpZmVfdHNibF9maWxsZWQgPC0gd2lsZGxpZmVfdHNibCAlPiUgZmlsbF9nYXBzKCkKCiMgZml0IG1vZGVsIGFuZCBnZW5lcmF0ZSBmb3JlY2FzdAp3aWxkbGlmZV9hcmltYSA8LSB3aWxkbGlmZV90c2JsX2ZpbGxlZCAlPiUgCiAgbW9kZWwoQVJJTUEodG90YWxfZXV0aCkpCgp3aWxkbGlmZV9mb3JlY2FzdCA8LSB3aWxkbGlmZV9hcmltYSAlPiUgCiAgZm9yZWNhc3QoaCA9IDM2KQoKIyBwbG90IGZvcmVjYXN0CndpbGRsaWZlX2Zjc3QgPC0gd2lsZGxpZmVfZm9yZWNhc3QgJT4lIAogIGFzX3RpYmJsZSgpICU+JSAKICBtdXRhdGUoc291cmNlID0gImZvcmVjYXN0IikKCmdncGxvdCgpICsKICBnZW9tX2xpbmUoZGF0YSA9IHdpbGRsaWZlX3RzYmxfZmlsbGVkLCBhZXMoeCA9IHllYXIsIHkgPSB0b3RhbF9ldXRoKSkgKwogIGdlb21fbGluZShkYXRhID0gd2lsZGxpZmVfZmNzdCwgYWVzKHggPSB5ZWFyLCB5ID0gLm1lYW4sIGNvbG9yID0gc291cmNlKSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJibGFjayIsICJyZWQiKSkgKwogIGxhYnModGl0bGUgPSAiQ2F0cyBFdXRoYW5pemVkIE92ZXIgVGltZSIsCiAgICAgICB4ID0gIlllYXIiLAogICAgICAgeSA9ICJOdW1iZXIgb2YgQ2F0cyBFdXRoYW5pemVkIikKCmBgYAoKYGBge3J9CgojIENvbnZlcnQgdG8gdHNpYmJsZSBvYmplY3QKd2lsZGxpZmVfdHNibCA8LSBhbmltYWxfb3V0Y29tZXMgJT4lCiAgZHJvcF9uYSgpICU+JQogIGZpbHRlcihhbmltYWxfdHlwZSA9PSAiQ2F0cyIgJiBvdXRjb21lID09ICJFdXRoYW5pemVkIikgJT4lCiAgZ3JvdXBfYnkoeWVhcikgJT4lCiAgc3VtbWFyaXNlKHRvdGFsX2V1dGggPSBzdW0obnVtYmVyX29mX29jY3VyZW5jZXMpKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgYXNfdHNpYmJsZShpbmRleCA9IHllYXIpCgojIENvbnZlcnQgdG8gdGltZSBzZXJpZXMgb2JqZWN0CndpbGRsaWZlX3RzIDwtIHRzKHdpbGRsaWZlX3RzYmwkdG90YWxfZXV0aCkKCiMgRml0IEFSSU1BIG1vZGVsCndpbGRsaWZlX2FyaW1hIDwtIHdpbGRsaWZlX3RzICU+JQogIG1vZGVsKEFSSU1BKQoKIyBHZW5lcmF0ZSBmb3JlY2FzdHMKd2lsZGxpZmVfZm9yZWNhc3QgPC0gd2lsZGxpZmVfYXJpbWEgJT4lCiAgZm9yZWNhc3QoaCA9IDM2KQoKIyBDb21iaW5lIG9ic2VydmVkIGRhdGEgYW5kIGZvcmVjYXN0cwp3aWxkbGlmZV9mY3N0IDwtIGJpbmRfcm93cygKICBhc190aWJibGUod2lsZGxpZmVfdHNibCksCiAgYXNfdGliYmxlKHdpbGRsaWZlX2ZvcmVjYXN0KSAlPiUgCiAgICByZW5hbWUodG90YWxfZXV0aCA9IC5tZWFuKQopICU+JSAKICBtdXRhdGUoc291cmNlID0gaWZfZWxzZShpcy5uYSh0b3RhbF9ldXRoKSwgIkZvcmVjYXN0IiwgIk9ic2VydmVkIikpCgojIFBsb3QgcmVzdWx0cwp3aWxkbGlmZV9mY3N0ICU+JQogIGdncGxvdChhZXMoeCA9IHllYXIsIHkgPSB0b3RhbF9ldXRoLCBjb2xvciA9IHNvdXJjZSkpICsKICBnZW9tX2xpbmUoKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoImJsdWUiLCAicmVkIikpICsKICBsYWJzKHggPSAiWWVhciIsIHkgPSAiVG90YWwgRXV0aGFuaXplZCBDYXRzIiwgY29sb3IgPSAiU291cmNlIiwgCiAgICAgICB0aXRsZSA9ICJUb3RhbCBFdXRoYW5pemVkIENhdHMgaW4gQXVzdGluLCBUWCIpICsKICB0aGVtZV9taW5pbWFsKCkKCmBgYApgYGB7cn0KCiMgQ29udmVydCB0cyBvYmplY3QgdG8gdHNpYmJsZQp3aWxkbGlmZV90c2JsIDwtIGFzX3RzaWJibGUod2lsZGxpZmVfdHMsIGluZGV4ID0gInllYXIiKQoKIyBGaXQgQVJJTUEgbW9kZWwgdG8gdHNpYmJsZQp3aWxkbGlmZV9hcmltYSA8LSB3aWxkbGlmZV90c2JsICU+JSAKICBtb2RlbChBUklNQSh2YWx1ZSkpCgojIEdlbmVyYXRlIGZvcmVjYXN0cwp3aWxkbGlmZV9mb3JlY2FzdCA8LSB3aWxkbGlmZV9hcmltYSAlPiUgCiAgZm9yZWNhc3QoaCA9IDM2KQoKIyBDb252ZXJ0IGZvcmVjYXN0IHRvIGEgdHNpYmJsZQp3aWxkbGlmZV9mY3N0IDwtIGFzX3RzaWJibGUod2lsZGxpZmVfZm9yZWNhc3QsIGtleSA9ICJ5ZWFyIikKCiMgUGxvdCB0aGUgZm9yZWNhc3QKd2lsZGxpZmVfZmNzdCAlPiUKICBnZ3Bsb3QoYWVzKHggPSB5ZWFyLCB5ID0gLm1lYW4sIGNvbG9yID0gc291cmNlKSkgKwogIGdlb21fbGluZSgpCgpgYGAKCmBgYHtyfQoKIyBDb252ZXJ0IHRzIG9iamVjdCB0byB0c2liYmxlCndpbGRsaWZlX3RzYmwgPC0gYXNfdHNpYmJsZSh3aWxkbGlmZV90cywgaW5kZXggPSAieWVhciIpCgojIEZpdCBBUklNQSBtb2RlbCB0byB0c2liYmxlCndpbGRsaWZlX2FyaW1hIDwtIHdpbGRsaWZlX3RzYmwgJT4lIAogIG1vZGVsKEFSSU1BKHZhbHVlKSkKCiMgR2VuZXJhdGUgZm9yZWNhc3RzCndpbGRsaWZlX2ZvcmVjYXN0IDwtIHdpbGRsaWZlX2FyaW1hICU+JSAKICBmb3JlY2FzdChoID0gMzYpCgojIENvbnZlcnQgZm9yZWNhc3QgdG8gYSB0c2liYmxlCndpbGRsaWZlX2Zjc3QgPC0gYXNfdHNpYmJsZSh3aWxkbGlmZV9mb3JlY2FzdCwga2V5ID0gInllYXIiKQoKIyBQbG90IHRoZSBmb3JlY2FzdAp3aWxkbGlmZV9mY3N0ICU+JQogIGdncGxvdChhZXMoeCA9IGluZGV4LCB5ID0gLm1lYW4sIGNvbG9yID0gLm1vZGVsKSkgKwogIGdlb21fbGluZSgpCgoKYGBgCgpgYGB7cn0KbmFtZXMod2lsZGxpZmVfZmNzdCkKCmxpYnJhcnkobHVicmlkYXRlKQpgYGAKCiMjIwoKYGBge3J9CiMgZ3JvdXBpbmcgdGhlIGRhdGEgYW5kIGNyZWF0aW5nIGEgdmFyaWFibGUKYW5pbWFsX2NvbXBsYWludHNfZ3JvdXBlZCA8LSBhbmltYWxfY29tcGxhaW50cyAlPiUgCiAgZ3JvdXBfYnkoZGF0ZV9yZWNlaXZlZCkgJT4lIAogIHN1bW1hcmlzZShjb3VudCA9IG4oKSkgJT4lIAogIGFycmFuZ2UoZGF0ZV9yZWNlaXZlZCkKCm15dHMgPC0gdHMoYW5pbWFsX2NvbXBsYWludHNfZ3JvdXBlZCRjb3VudCwgZnJlcXVlbmN5ID0gMTIsIHN0YXJ0ID0gYyh5ZWFyKGFuaW1hbF9jb21wbGFpbnRzX2dyb3VwZWQkZGF0ZV9yZWNlaXZlZFsxXSksIG1vbnRoKGFuaW1hbF9jb21wbGFpbnRzX2dyb3VwZWQkZGF0ZV9yZWNlaXZlZFsxXSkpKQoKbXlmb3JlY2FzdCA8LSBmb3JlY2FzdChhdXRvLmFyaW1hKG15dHMpLCBoID0gMjQpCgoKcGxvdChteWZvcmVjYXN0LCBtYWluID0gIkZvcmVjYXN0ZWQgdmFsdWVzIikKCmBgYAoKCmBgYHtyfQpteXRzX2ZvcmVjYXN0IDwtIGZ1bmN0aW9uKG15dHMsIGgsIGludGVydmFsKSB7CiAgbGlicmFyeShmb3JlY2FzdCkKICAKICAjIFNldCB0aGUgYXBwcm9wcmlhdGUgdGltZSBpbnRlcnZhbCBmb3IgdGhlIGZvcmVjYXN0IGhvcml6b24KICBpbnRlcnZhbCA8LSBzd2l0Y2goaW50ZXJ2YWwsCiAgICAgICAgICAgICAgICAgICAgICJkYXkiID0gImRheXMiLAogICAgICAgICAgICAgICAgICAgICAiaG91ciIgPSAiaG91cnMiLAogICAgICAgICAgICAgICAgICAgICAibWludXRlIiA9ICJtaW5zIiwKICAgICAgICAgICAgICAgICAgICAgInNlY29uZCIgPSAic2VjcyIpCiAgCiAgIyBDcmVhdGUgdGhlIGZvcmVjYXN0CiAgbXlmb3JlY2FzdCA8LSBmb3JlY2FzdChteXRzLCBoID0gMjQsIGxldmVsID0gYyg4MCwgOTUpLCAKICAgICAgICAgICAgICAgICAgICAgICB4cmVnID0gbXlkdW1taWVzLCAKICAgICAgICAgICAgICAgICAgICAgICBsYW1iZGEgPSBOVUxMLCBiaWFzYWRqID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICBmYW4gPSBGQUxTRSwgCiAgICAgICAgICAgICAgICAgICAgICAgaW50ZXJ2YWwgPSAid2VlayIpCgogIAogICMgUHJpbnQgdGhlIGZvcmVjYXN0IHRhYmxlCiAgcHJpbnQobXlmb3JlY2FzdCkKICAKICAjIFBsb3QgdGhlIGZvcmVjYXN0CiAgYXV0b3Bsb3QobXlmb3JlY2FzdCkKfQoKYGBgCgpgYGB7cn0KcHJpbnQoaW50ZXJ2YWwpCnByaW50KGNsYXNzKGludGVydmFsKSkKcHJpbnQobGVuZ3RoKGludGVydmFsKSkKYGBgCgpgYGB7cn0KIyBDcmVhdGUgYSBzZXF1ZW5jZSBvZiBkYXRlcyBmb3IgdGhlIG5leHQgMjQgbW9udGhzCmRhdGVzIDwtIHNlcShhcy5EYXRlKCIyMDIzLTAzLTAxIiksIGJ5ID0gIm1vbnRoIiwgbGVuZ3RoLm91dCA9IDI0KQoKIyBDcmVhdGUgYSB0aW1lIHNlcmllcyBvYmplY3Qgd2l0aCByYW5kb20gdmFsdWVzIGZvciBkZW1vbnN0cmF0aW9uIHB1cnBvc2VzCnZhbHVlcyA8LSBybm9ybSgyNCkKbXl0cyA8LSB0cyh2YWx1ZXMsIHN0YXJ0ID0gYyh5ZWFyKGRhdGVzWzFdKSwgbW9udGgoZGF0ZXNbMV0pKSwgZnJlcXVlbmN5ID0gMTIpCgojIFBsb3QgdGhlIHRpbWUgc2VyaWVzCnBsb3QobXl0cykKCiMgRm9yZWNhc3QgdGhlIG5leHQgMjQgbW9udGhzCmxpYnJhcnkoZm9yZWNhc3QpCm15Zm9yZWNhc3QgPC0gZm9yZWNhc3QobXl0cywgaCA9IDI0KQoKIyBQbG90IHRoZSBmb3JlY2FzdGVkIHZhbHVlcwpwbG90KG15Zm9yZWNhc3QpCgpgYGAKCgoKIyMjIEFub3RoZXIsIEZJTkFMIGF0dGVtcHQKClRoaXMgaXMgcXVpdGUgZGlmZmljdWx0IGluZGVlZC4gTGV0J3MgdHJ5IGdvIHNsb3dseSB1c2luZyB0aGUgbm90ZXMsIGJ1aWxkIGl0IGJpdCBieSBiaXQuCgpgYGB7cn0KbGlicmFyeShmZWFzdHMpCgphbmltYWxfY29tcGxhaW50c19ncm91cGVkIDwtIGFuaW1hbF9jb21wbGFpbnRzX2dyb3VwZWQgJT4lIAogIGRyb3BfbmEoKQpgYGAKClNvIGFsbCB3ZSB3YW5uYSBkbywgaXMgcGxvdCB0aGUgbmV4dCBmZXcgeWVhcnMsIGFuZCBzZWUgd2hhdCBpdCB3aWxsIGxvb2sgbGlrZSBvbiB0aGUgZ3JhcGguIE5vdGhpbmcgbmVlZHMgdG8gYmUgdG9vIGZhbmN5LiBXZSB3aWxsIGtlZXAgaXQgc2ltcGxlLCBjcmVhdGUgYSBzaW1wbGUgbW9kZWwuIFRoZW4gcGxvdCB0aGlzLiBPSy4KClNvIGZpcnN0LCBpdCBuZWVkcyB0byBiZSB0c2liYmxlLgpgYGB7cn0KYW5pbWFsX2NvbXBsYWludHNfdHNpYmJsZSA8LSBhc190c2liYmxlKGFuaW1hbF9jb21wbGFpbnRzX2dyb3VwZWQsIGluZGV4ID0gZGF0ZV9yZWNlaXZlZCkKCmFuaW1hbF9jb21wbGFpbnRzX3RzaWJibGUgPC0gYW5pbWFsX2NvbXBsYWludHNfdHNpYmJsZSAlPiUgCiAgbXV0YXRlKGRhdGVfcmVjZWl2ZWQgPSB0c2liYmxlOjp5ZWFybW9udGgoZGF0ZV9yZWNlaXZlZCkpICU+JSAKICBtdXRhdGUoY291bnQgPSBhcy5kb3VibGUoY291bnQpKQpgYGAKCkl0IGhhcyBub3cgYmVlbiBjb252ZXJ0ZWQgdG8gYSB0c2liYmxlLCB3aXRoIGRhdGVfcmVjZWl2ZWQgYXMgdGhlIGluZGV4LiBBcyBpdCBjb250YWlucyBvbmx5IGEgc2luZ2xlIHRpbWUgc2VyaWVzLCBhIGtleSBzaG91bGQgbm90IGJlIG5lY2Vzc2FyeS4KCmBgYHtyfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShmYWJsZSkKbGlicmFyeSh0c2liYmxlKQpsaWJyYXJ5KHRzaWJibGVkYXRhKQojIFdlIGFsc28gbmVlZCB0byB1c2UgdGhlICJ1cmNhIiBwYWNrYWdlIHRvIGJlIGFibGUgdG8gdXNlIHRoZSBBUklNQSBtb2RlbApsaWJyYXJ5KHVyY2EpCmBgYAoKV2UgbG9hZCBpbiBhbGwgcGFja2FnZXMganVzdCB0byBiZSAxMDAlIHN1cmUgdGhleSBhcmUgbG9hZGVkLiAKCmBgYHtyfQojIG5vIG5lZWQgdG8gZGVzZWxlY3QgdmFyaWFibGVzOyB3ZSBhbHJlYWR5IGhhdmUgdGhlIG9ubHkgMiB3ZSB3aWxsIG5lZWQuCgojIG5leHQsIHdlIHdpbGwgdXNlIGF1dG9wbG90CmF1dG9wbG90KGFuaW1hbF9jb21wbGFpbnRzX3RzaWJibGUpCmBgYAoKT3VyIGRhdGEgaXMgdGhlcmUuIE5vdywgd2Ugd2lsbCBmaXQgYSBtb2RlbC4KCmBgYHtyfQpsaWJyYXJ5KHB1cnJyKQoKZml0IDwtIGFuaW1hbF9jb21wbGFpbnRzX3RzaWJibGUgJT4lCiAgbW9kZWwoCiAgICBzbmFpdmUgPSBTTkFJVkUoY291bnQpLAogICAgbWVhbl9tb2RlbCA9IE1FQU4oY291bnQpLAogICAgYXJpbWEgPSBBUklNQShjb3VudCkKICApCmZpdAoKIyBmaXQgJT4lIAojICAgZG1hcCh1bmxpc3QpCmBgYAoKSGVyZSBpcyBvdXIgbWFibGUsIGFsc28gY2FsbGVkIG1vZGVsIHRhYmxlLiBFYWNoIGNlbGwgY29ycmVzcG9uZHMgdG8gYSBmaXR0ZWQgbW9kZWwuIE5vdywgd2Ugd2lsbCBjYWxjdWxhdGUgc29tZSBmb3JlY2FzdHMgdXNpbmcgb3VyIG1vZGVsLgoKYGBge3J9CmZvcmVjYXN0XzEgPC0gZml0ICU+JQogIGZhYmxldG9vbHM6OmZvcmVjYXN0KGggPSAzNikKZm9yZWNhc3RfMQpgYGAKCk9LLCBsb29raW5nIGdvb2Qgc28gZmFyLgoKYGBge3J9CmZvcmVjYXN0XzEgJT4lCiAgYXV0b3Bsb3QoYW5pbWFsX2NvbXBsYWludHNfdHNpYmJsZSkKYGBgCgpMZXQncyBtYWtlIG91ciBtb2RlbCBsb29rIHByZXR0eSBhbmQgaGF2ZSBsZXNzIGNsdXR0ZXIKCmBgYHtyfQpmb3JlY2FzdF8xICU+JQogIGZpbHRlcigubW9kZWwgPT0gImFyaW1hIikgJT4lIAogIGF1dG9wbG90KGFuaW1hbF9jb21wbGFpbnRzX3RzaWJibGUsIGxldmVsID0gOTUpICsKICBzY2FsZV94X3llYXJtb250aChkYXRlX2JyZWFrcyA9ICI2IG1vbnRocyIsIGRhdGVfbGFiZWxzID0gIiViICV5IikgKyAKICBsYWJzKHRpdGxlID0gIlRvd25zdmlsbGUgQ29tcGxhaW50IENhbGxzIHdpdGggUHJlZGljdGlvbiIsCiAgICAgICB4ID0gIlRpbWUiLAogICAgICAgeSA9ICJOdW1iZXIgb2YgQ2FsbHMiKSArCiAgdGhlbWVfZWNvbm9taXN0KCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIHZqdXN0ID0gMSwgZmFtaWx5ID0gIm1vbm8iLCBmYWNlID0gImJvbGQiLCBzaXplID0gNyksCiAgICAgICAgI2F4aXMudGlja3MueCA9IAogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dCh2anVzdCA9IDMuMiksCiAgICAgICAgdGl0bGUgPSBlbGVtZW50X3RleHQoZmFtaWx5ID0gIm1vbm8iLCBmYWNlID0gImJvbGQiKSwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC40KSwKICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArCiAgICAgICAgYW5ub3RhdGUoInJlY3QiLCB4bWluID0gYXMuRGF0ZSgiMjAxNC0wNi0wMSIpLCB4bWF4ID0gYXMuRGF0ZSgiMjAxNC0wOC0wMSIpLCB5bWluID0gLUluZiwgeW1heCA9IEluZiwgZmlsbCA9ICJncmF5NzAiLCBhbHBoYSA9IDAuMykgKwogICAgICAgIGFubm90YXRlKCJyZWN0IiwgeG1pbiA9IGFzLkRhdGUoIjIwMTUtMDYtMDEiKSwgeG1heCA9IGFzLkRhdGUoIjIwMTUtMDgtMDEiKSwgeW1pbiA9IC1JbmYsIHltYXggPSBJbmYsIGZpbGwgPSAiZ3JheTcwIiwgYWxwaGEgPSAwLjMpICsKICAgICAgICBhbm5vdGF0ZSgicmVjdCIsIHhtaW4gPSBhcy5EYXRlKCIyMDE2LTA2LTAxIiksIHhtYXggPSBhcy5EYXRlKCIyMDE2LTA4LTAxIiksIHltaW4gPSAtSW5mLCB5bWF4ID0gSW5mLCBmaWxsID0gImdyYXk3MCIsIGFscGhhID0gMC4zKSArCiAgICAgICAgYW5ub3RhdGUoInJlY3QiLCB4bWluID0gYXMuRGF0ZSgiMjAxNy0wNi0wMSIpLCB4bWF4ID0gYXMuRGF0ZSgiMjAxNy0wOC0wMSIpLCB5bWluID0gLUluZiwgeW1heCA9IEluZiwgZmlsbCA9ICJncmF5NzAiLCBhbHBoYSA9IDAuMykgKwogICAgICAgIGFubm90YXRlKCJyZWN0IiwgeG1pbiA9IGFzLkRhdGUoIjIwMTgtMDYtMDEiKSwgeG1heCA9IGFzLkRhdGUoIjIwMTgtMDgtMDEiKSwgeW1pbiA9IC1JbmYsIHltYXggPSBJbmYsIGZpbGwgPSAiZ3JheTcwIiwgYWxwaGEgPSAwLjMpICsKICAgICAgICBhbm5vdGF0ZSgicmVjdCIsIHhtaW4gPSBhcy5EYXRlKCIyMDE5LTA2LTAxIiksIHhtYXggPSBhcy5EYXRlKCIyMDE5LTA4LTAxIiksIHltaW4gPSAtSW5mLCB5bWF4ID0gSW5mLCBmaWxsID0gImdyYXk3MCIsIGFscGhhID0gMC4zKSArCiAgICAgICAgYW5ub3RhdGUoInJlY3QiLCB4bWluID0gYXMuRGF0ZSgiMjAyMC0wNi0wMSIpLCB4bWF4ID0gYXMuRGF0ZSgiMjAyMC0wOC0wMSIpLCB5bWluID0gLUluZiwgeW1heCA9IEluZiwgZmlsbCA9ICJncmF5NzAiLCBhbHBoYSA9IDAuMykgKwogICAgICAgIGFubm90YXRlKCJyZWN0IiwgeG1pbiA9IGFzLkRhdGUoIjIwMjEtMDYtMDEiKSwgeG1heCA9IGFzLkRhdGUoIjIwMjEtMDgtMDEiKSwgeW1pbiA9IC1JbmYsIHltYXggPSBJbmYsIGZpbGwgPSAiZ3JheTcwIiwgYWxwaGEgPSAwLjMpICsKICAgICAgICBhbm5vdGF0ZSgicmVjdCIsIHhtaW4gPSBhcy5EYXRlKCIyMDIyLTA2LTAxIiksIHhtYXggPSBhcy5EYXRlKCIyMDIyLTA4LTAxIiksIHltaW4gPSAtSW5mLCB5bWF4ID0gSW5mLCBmaWxsID0gImdyYXk3MCIsIGFscGhhID0gMC4zKSArCiAgICAgICAgYW5ub3RhdGUoInJlY3QiLCB4bWluID0gYXMuRGF0ZSgiMjAyMy0wNi0wMSIpLCB4bWF4ID0gYXMuRGF0ZSgiMjAyMy0wOC0wMSIpLCB5bWluID0gLUluZiwgeW1heCA9IEluZiwgZmlsbCA9ICJncmF5NzAiLCBhbHBoYSA9IDAuMykKICAgICAgICAgICAgICAgICAgICAgICAgCmBgYAoKU28gSSB3YXMgYWxzbyB0YXNrZWQgd2l0aCBjcmVhdGluZyBhIG1vZGVsLCB0byBwcmVkaWN0IGhvdyB0aGluZ3MgbWlnaHQgbG9vayBmb3IgdGhlIG5leHQgZmV3IHllYXJzLiBJIGZvY3VzZWQgc3BlY2lmaWNhbGx5IG9uIHRoZSBUb3duc3ZpbGxlIGRhdGEsIGFzIHRoaXMgd2FzIG1vc3Qgc3VpdGFibGUgZm9yIGZvcmVjYXN0aW5nLiBJIHVzZWQgc29tZXRoaW5nIGNhbGxlZCB0aGUgIkFSSU1BIiBtb2RlbCwgdGhlIGlubmVyIHdvcmtpbmdzIG9mIHdoaWNoIGFyZSBxdWl0ZSBjb21wbGljYXRlZCwgYnV0IGJhc2ljYWxseSBpdCBwcmVkaWN0cyB0aGUgZnV0dXJlIGJhc2VkIG9uIHRoZSBwYXN0LCBhbmQgaXMgcXVpdGUgZ29vZCB3aGVuIGl0IGNvbWVzIHRvIHNlYXNvbmFsIGRhdGEgbGlrZSBJIGhhdmUgaGVyZS4gVGhlIGJsdWUgbGluZSBpcyB0aGUgcHJlZGljdGlvbiwgYW5kIHRoZSBsaWdodCBibHVlIGFyZWEgeW91IHNlZSBoaWdobGlnaHRlZCBhcm91bmQgaXQgaXMgdGhlIGNvbmZpZGVuY2UgaW50ZXJ2YWwuIFRoaW5rIG9mIHRoaXMgbGlrZSBhIG1hcmdpbiBvZiBlcnJvciwgYW5kIGl0IGJhc2ljYWxseSBtZWFucyB0aGF0IDk1JSBvZiB0aGUgdGltZSwgb3VyIG1vZGVsIHdpbGwgcHJlZGljdCByZXN1bHRzIGluIHRoaXMgYXJlYS4KClRoaXMgbW9kZWwgc3VnZ2VzdHMgdGhhdCByb3VnaGx5IHRoZSBzYW1lIHBhdHRlcm4gd2lsbCBjb250aW51ZSBhcyBiZWZvcmUsIHdpdGggZmFpcmx5IHN0ZWFkeSB2b2x1bWUgb2YgY2FsbHMgYW5kIGhpZ2ggcGVha3MgaW4gV2ludGVyLiBCdXQgYmVhciBpbiBtaW5kIHRoaXMgbW9kZWwgaXMgcXVpdGUgbGltaXRlZCBhbmQgc2hvdWxkbid0IGJlIHRha2VuIGFzIGZhY3Q7IGZvciBleGFtcGxlLCBpdCBkb2Vzbid0IHRha2UgaW50byBhY2NvdW50IG5hdHVyYWwgZGlzYXN0ZXJzIGFuZCBvdGhlciBldmVudHMgd2hpY2ggY291bGQgY2F1c2UgYW4gaW5jcmVhc2UgaW4gY29tcGxhaW50IGNhbGxzLgoKCgojIyMgRG9jdW1lbnRhdGlvbiBub3RlCgpGaXggb3IgZGlzY3VzcyB0aGUgZXJyb3Igb2YgTlQgYW5kIE5TVyBzd2FwcGluZyBmb3IgMjAxNi0yMDE4CgpgYGB7cn0KYW5pbWFsX291dGNvbWVzICU+JSAKICBtdXRhdGUocmVnaW9uID0gaWYoKSkKYGBgCgo=